摘要:岁末年初,Linux内核2024年度盘点如约而至。继《2022 Linux内核十大技术革新功能 | 年终盘点》、《熠熠生辉 | 2023 Linux 内核十大技术革新功能
【CSDN 编者按】岁末年初,Linux内核2024年度盘点如约而至。继《2022 Linux内核十大技术革新功能 | 年终盘点》、《熠熠生辉 | 2023 Linux 内核十大技术革新功能
》之后,知名Linux内核一线开发者,经典书籍《Linux 设备驱动开发详解》作者宋宝华老师又给大家带来了2024年Linux内核开发中,十个最典型的patchset,为大家呈现干货满满的硬核技术年货。作者 | 宋宝华 责编 | 梦依丹
出品 | CSDN(ID:CSDNnews)
在世界的一个偏远角落,新西兰南岛的Wanaka湖如一颗孤独的宝石镶嵌在大地上。而湖中那棵孤独的树,静静伫立在浅水间,仿佛是地球尽头的守望者。四周广袤无垠,无林相依,无藤缠绕,它以一种近乎倔强的姿态,迎风而立。
枝干瘦削,却如挣脱束缚的手臂,向广袤的天空伸展。它的孤独与悲凉在这偏远之地更显深邃,仿佛这世界的尽头只剩它与时间对峙。没有喧嚣的回应,也无同行的影子,它孤独却不卑微,悲凉却无敌。
Linux内核,从未屈从于商业利益,也未受垄断规则束缚。它以开源与自由为根基,犹如孤高的旅者,坚定攀登技术巅峰。没有资本巨头的庇护,却汇聚全球开发者,以协作书写代码的史诗。它的孤独,是独辟蹊径的荣耀;它的倔强,是拒绝停滞的信念。2024年的Linux内核,在时代洪流中岿然不动,以创新点燃自由与协作的光芒。
依据往年的惯例,本文依然选取2024年Linux内核社区的十个创新点进行描述,排名不分先后。
文件系统支持比page size更大的block size
zeromap、mTHP swap allocator、swap slots在unmap批量释放
延迟抢占调度PREEMPT_LAZY
公平调度类EEVDF的系列完善
device mem TCP
内核空间内存profiler:memprofiling
mTHP的系列进展
block I/O无撕裂的原子写
sched_ext BPF调度的系列进展
最后一个彩蛋: kernel panic二维码
下面分别展开论述。
文件系统支持比page size更大的block size
一般情况下,Linux文件系统的block size是要小于或者等于page size的,否则可能出现很多partial reads/writes,比如一个partial write就需要涉及到Read-Modify-Write,读出老的内容、与新内容merge、写入老新内容merge后的结果。但是硬件的发展有时候需要push软件的前进,在高速SSD中,IU(indirection unit)可能能以大于4KiB的粒度(如16KiB、64KiB)完成LBA(logical block address)到物理位置的转换,从而提高性能。这种IU单元完成的地址转化对均衡化真实I/O发生的物理位置、提高器件寿命十分重要[1]既然硬件支持了比page size更大粒度的block size,软件还顽固地给它们4KiB的page去读写,势必因为partial I/Os问题影响性能。
由于Linux内核已经支持large folios,page cache中也可直接填充large folios,这样page cache这层应该可以直接可以给底层文件系统大于或者等于block size的large folios,从而规避partial reads/writes问题。这个里面的先行者就是xfs文件系统。
在Pankaj Raghav等人的patchset中[2],xfs主要要告诉page cache,文件系统支持的最小order是什么(通常就是block size对应的order):
并且我们需要阻止这种文件系统上面page cache里面的large folios被split为0-order,它必须至少split到min_order:
因为我们透过mapping_set_folio_min_order告知了page cache层我们这个文件系统支持的order的range:
这样page cache那层申请内存的时候,就会满足这个range:
page cache的处理,也会以对齐的粒度进行操作:
注意bs(block size) > ps(page size)的支持,本质上与文件系统支持large folios不是一回事,因为后者更加着重强调bs
2024年,我们也要感谢高翔在erofs针对压缩文件支持了large folios和其他在各个文件系统尝试large folios支持的人们。
零内容页swap优化、mTHP swap allocator、swap slots在unmap批量释放
2.1 零内容folio透过zeromap在swap out/in过程中免I/O
这不一定是完全新鲜的内容,早先zswap和zRAM已经提供了对内容是0(以及内容全相等)的页面swap out和swap in的免I/O支持。这一次,zeromap把这个功能进行了抽象,让所有的swap设备都可以免I/O。
在Usama Arif 的patchset中[3],它为每个swapfile申请了一个bitmap,用1个bit来描述一个swap entry是否是0。在swap out的过程中,判断folio的内容是否为0,如果是0,则在bitmap中写入相应的bit为1:
在swap in的时候,如果发现bitmap是设置的,则直接对swap in的folio填充0:
很多情况下,swap out的folio可能有超过10%其实是全0的,前面的zeromap直接skip了zswap, zRAM以及其他的swap file。这样的swap过程,在统计上可能消失了,对profiling userspace的性能问题时,可能造成困扰,在笔者的patch中[4],对这个问题进行了修正,于内核中新增了swpout_zero和swpin_zero计数。2.2 mTHP swap-out情况下swap allocator
当large folios成为一个主流的开发趋势,一个mTHP在swap-out的时候,应该尽可能以一个整体被交换出去。目前的内核依赖于申请到与folio size同等大小的连续的swap slots。
经过笔者开发的tools/mm/thp_swap_allocator_test.c的实际测试[5],Linux mTHP swapout的整体交换成功率非常低,fallback率很快接近100%:究其原因,是因为原先的Linux必须找到一个空的swap cluster(通常是2MB),才能给1个mTHP,哪怕这个mTHP只有16KiB。这显然是不靠谱的。
这个时候,Google的Chris Li和腾讯的Kairui Song童鞋迎难而上,他们做的工作是将swap_cluster进行归类,比如这个swap_cluster申请过16KB的mTHP,以后就主攻16KB mTHP的swap,这样部分空(非全空)的swap cluster也还是可以被mTHP用到的[6]。这里面比较核心的一个patch是mm: swap: mTHP allocate swap entries from nonfull list,在内核原先的free cluster的list基础上,增加了nonfull cluster的list:
它也在swap_cluster_info增加了order来表面这个cluster倾向的分配mTHP swapout的order。
这样给mTHP的swap out申请swap slots的时候,也可以找nonfull的cluster:
注意在if (!list_empty)的路径上,一个空的cluster首次被mTHP swapout申请走的时候,ci->order = order,这记住了这个swap cluster的倾向性。
2.3 unmap批量释放mTHP的连续swap entries
在前面Kairui Song工作的基础上,笔者继续完成了unmap路径上的swap entries批量释放[7]:从而有效提高了swap-filled的PTEs的unmap速度3倍:
延迟抢占调度PREEMPT_LAZY
过多的抢占会牺牲吞吐、增加lock contention,过少的抢占会增大延迟。人们一直在探索不同的抢占模型以适应不同的业务需求。
PREEMPT_LAZY是一种位于PREEMPT_VOLUNTARY(Voluntary Kernel Preemption (Desktop)和PREEMPT(Preemptible Kernel (Low-Latency Desktop))之间的机制:
它让normal/fair调度类的工作接近于PREEMPT_VOLUNTARY(但是不完全相同,下一个tick来的时候,normal/fair在内核态仍然可以抢占),让其他的实时调度类如RR/FIFO/DEADLINE仍然采用PREEMPT。这一点从PREEMPT_LAZY的描述可以看出:
所以假设没有PREEMPT_LAZY的情况下(PREEMPT情况),fair调度类的task b本身可以在时刻1抢占task a,而随着PREEMPT_LAZY的引入,这个抢占需要延迟到下一个tick的到来。
PREEMPT_LAZY由Peter Zijlstra的“sched: Lazy preemption muck ”patchset[8]完成。在其中的patch“sched: Add TIF_NEED_RESCHED_LAZY infrastructure”中,Peter将原先的TIF_NEED_RESCHED分为2个flag:
n _TIF_NEED_RESCHED:保持原先的行为;
n _TIF_NEED_RESCHED_LAZY:让抢占延后到tick发生。
当然,return-to-user的时候这种常规非内核态抢占,以上二者都是允许的。
在“sched: Add Lazy preemption model”这个patch中,fair调度类的抢占需求要设置TIF_NEED_RESCHED_LAZY,等待tick到来的时候抢占,这使得平均抢占延迟为TICK_NSEC/2。RR/FIFO/DEADLINE调度类的行为不会被改变。
等待tick到来的时候,哪怕是_TIF_NEED_RESCHED_LAZY也会被强制调用resched_curr设置为_TIF_NEED_RESCHED:
其他的时候,都只是调用resched_curr_lazy:
在__resched_curr里面,_TIF_NEED_RESCHED_LAZY只有碰到idle类的任务的时候,才会设置抢占标记(对单核而言只是简单地设置need_resched,对多核而言,则可能透过smp_send_reschedule通知别的cpu进行抢占调度):
Peter首先仅在x86支持PREEMPT_LAZY,ARM64对这一抢占模型的支持方式还在激烈讨论中[9]。公平调度类EEVDF的系列完善
我们都知道Earliest Virtual Deadline First (EEVDF) 已经完全取代 Completely Fair Scheduler (CFS) ,EEVDF总是调度虚拟截止时间最近的任务,而不是虚拟运行时间最小的任务,它考虑了任务对延迟的诉求。
EEVDF是Earliest Eligible Virtual Deadline First的缩写,它同时追求CFS追求的fairness(公平性),但是也强调 interactivity(交互性)。
EEVDF仍然强调公平,比如5个nice值相同的各跑20%的CPU。但是公平其实可以被另外一种方式来实现,CFS的算法是谁的虚拟运行时间最小,就跑谁(欠谁的钱多,先还谁);而EEVDF则优先跑虚拟截止时间最小的任务(谁催债催地最急,先还谁。理论上讲,欠的最多的也大抵是催地最急的)。
EEVDF引入的一个新概念叫做“lag”(滞后),所谓滞后,就是任务还没有收到它理应的配额(比如20%还只跑了15%),只有lag值为正数的任务才是“eligible”(有资格)可以跑的,lag为负数证明那个任务已经跑超过配额了。
lag = 理想情况下应该跑的时间 - 实际跑的时间
假设现在某CPU上面有3个任务在跑CPU-bound的工作,在0时刻,最开始它们的lag都是0:
现在假设先让t1跑30ms的timeslice,在30ms这个时刻,3个任务的lag将变成:
现在假设我们挑选t2跑30ms的timeslice,在60ms这个时刻,3个任务的lag将变为:
这样看起来,接下来系统会跑lag=20ms的t3。在30ms时刻,t1的lag是-20ms,而在60ms的时刻,t1的lag decay(衰减)到了-10ms,其实再衰减一段时间,它的lag会变成0,t1会再次eligible。
Linux在6.6内核就引入了EEVDF,但是到6.12才宣布“Complete the EEVDF task scheduler”。在6.12的complete patchset[10]中,最主要的一个工作是完善睡眠任务的lag。EEVDF需要维护lag,来判定一个任务是否eligible。在一个任务进入睡眠后,再次醒来,它前面的lag还在吗?这个时候我们有2个选择:
1. 直接在醒来时候忘记之前的lag,让lag归0,但是这会导致一个前面比如lag为负的任务,通过极其短暂的睡眠再醒来,lag就归0了,于是它可能过度运行;
2. 直接在醒来时候完全采用睡眠之前的lag,但是一个任务睡了一整天,就因为它昨天的lag是负数,今天还要继续惩罚它,似乎也不合理。
我们都知道,当一个任务变成睡眠态的时候,应该执行sched_class的dequeue。而对于EEVDF,Peter采用的渠道是,如果任务的lag为负(它跑超额了,显然也是不eligible),让进入睡眠的任务不直接dequeue;而是进入一个deferred dequeue的状态,在deferred dequeue状态的任务的lag还是会decay(衰减)的。
随着时间的推移,一个lag为负的任务的lag会decay到0,才真正执行dequeue。理论上lag退化0的点就需要dequeue,但是这在实现上比较困难,所以Peter的实现逻辑是workaround的,在deferred dequeue的任务下一次被pick出来的时候dequeue。
device mem TCP
Device Memory TCP (devmem TCP)完成了2个目标:
通过网络发送设备memory。底层的设备memory采用dma-buf机制。
通过网络接收设备memory并直接存入本地的设备memory。
因此,它是一种Direct-to-device的网络方法。
我们知道dma-buf提供了一种本机内部设备与设备、设备与设备共享内存的方法,之前笔者已经在《世上最好的共享内存(Linux共享内存最透彻的一篇)》中有论述。简单地来说,dma_buf可以实现buffer在多个设备的共享,应用可以把一片底层驱动A的buffer导出到用户空间成为一个fd,也可以把fd导入到底层驱动 B。当然,如果进行mmap得到虚拟地址,CPU也是可以在用户空间访问到已经获得用户空间虚拟地址的底层buffer的。
devmem TCP实际上把dma-buf的传输扩展到的网络上并非本机的设备、CPU之间了。由于是A机器的dma-buf送到B机器的dma-buf,这样避免了设备的dma-buf和host buffer之间的拷贝[11]。跨节点的device到device的传输,在下面的一些应用场景中可能受益:
分布式训练,即在不同主机上的机器学习加速器(如GPU)之间交换数据。
分布式raw block storage应用与远程SSD传输大量数据。其中大部分数据不需要主机处理。
这个patchset由Google的Mina Almasry完成[12],一共迭代了24版。接收端的网卡应支持header的自动分离,并且支持flow steering 、RSS,确保目标是devmem的网络包能流向正确的RX queue。# 使能header splitethtool -G eth1 tcp-data-split on# 使能flow steeringethtool -K eth1 ntuple on#配置RSSethtool --set-rxfh-indir eth1 equal 15ethtool -N eth1 flow-type tcp4 ... queue 15接收端的应用程序通过netlink,绑定NIC的RX queue和dma-buf:
应用程序ret = recvmsg(fd, &msg, MSG_SOCK_DEVMEM);接收。
在patch “netdev: support binding dma-buf to netdevice”中,支持了dma-buf和NIC RX queue的绑定:
patch “tcp: RX path for devmem TCP”会完成,接收到的packet装填到dma-buf的工作。主要函数tcp_recvmsg_devmem,把skb的header剥离开,放到一片linear的buffer,通过cmsg告诉用户linear buffer的bytes数;通过dmabuf_cmsg告诉用户dma-buf里面数据的offset、size和token。
接收端的用户程序,通过这些cmsg可以知道究竟收到了多少数据,收到哪个位置了等:
AI大模型时代,围绕dma-buf的各种优化,应该仍然有很大的空间。大模型占据大量的dma-buf内存,涉及很大的I/O。如何在省内存、加速I/O方面进行优化,应该是一个很好的探索方向。
这是由Kent Overstree和 Google的Suren Baghdasaryan完成的一个内核空间内存使用情况的剖析器[13][14],它可以直观地给出内核空间的内存被谁申请走,申请的各个对象有多少个等:其实所有的这种profiler都面临一个问题,怎么记住谁分配了什么东西的问题,当然这个记录的成本越低越好,最好低到不仅仅在调试阶段可以用,而且允许部署到真实产品。
在Memory allocation profiling这个patchset,它实现了一个所谓的code taggging库,以一些数据结构记录各种内存分配调用者的module名、文件名、函数名、申请的行号。
由于code tags就是一些线性的数组,所以迭代它也比较简单:
尔后在所谓的codetag上面继续封装了一种alloc_tag:
其实就是在前面的codetag上面加了个计数器:分配了多少bytes,这个codetag(分配的代码位置)发生了多少次calls。在codetag再次命中同一个位置的时候,进行计数:
替换具体的分配函数,每次分配时候运行一个hook,来进行tag:
这个里面比较关键的看起来就是DEFINE_ALLOC_TAG:
进一步展开
所以这些tag的信息,其实是在编译的预处理阶段就已经填充进去了,并不是运行时依赖debug信息反向解析出来的文件名,函数名,行号之类的。
在内存分配和释放的后续处理路径上,分别进行alloc_tag的add和sub:
这里面读者可能会有个疑惑,比如我怎么根据我的alloc_tag快速知道我在tag区的偏移是多少?难道需要快速迭代codetag区,然后比对我的tag的函数名、行号等信息与某个tag的一致,从而得到它在tag数组里面的位置,最后在正确的tag位置加1和减1 ?
这样开销未免就有点太大了,其实仔细看DEFINE_ALLOC_TAG的定义,它定义的是一个static struct alloc_tag _alloc_tag的,关键是static,而且link在一个特定的section里面:__section(ALLOC_TAG_SECTION_NAME),所以,用我的tag地址,减去section的开始地址就差不多得到tag在线性区域的存放位置了。
显然Memory allocation profiling的实现技巧上主要利用了编译的预处理和link特殊section的小法术tricks,来减小实现时候的CPU开销。
mTHP的系列进展
large folios/mTHP相关的工作在2024的Linux社区持续进行:
阿里巴巴的Baolin Wang在shmem上提供了mTHP支持[15]Lance Yang提供了MADV_FREE(lazyfree)的mTHP不分裂支持[16],不过这个工作还是有一个不完善的地方,最终在内存回收try_to_unmap_one的时候,lazyfree的mTHP还是会被加入deferred_split list,笔者的“mm: batched unmap lazyfree large folios during reclamation” patchset正在完善这一部分[17]。
笔者和Chuanhua Han(OPPO的工作)的large folios swap-in: handle refault cases first[18]与mm: enable large folios swap-in support[19]支持mTHP的swap in。
阿里巴巴的Baolin Wang在mTHP的NUMA Balancing支持[20]
Intel的Kanchana P Sridhar的zswap的mTHP swap-out支持[21]
…
block I/O无撕裂的原子写
MySQL,PostgreSQL等数据库,一次性要写入1个16KiB的chunk,假设page size和block size是4KiB,这相当于要写4个blocks。如果这些写入不是原子的(要么全写入成功,要么全部都没写入),而出现了部分写入现象,就无法保证数据的一致性。这个原理可以类比文件系统的metadata和data的写入,如果metadata和data的写入不能都完成,则文件系统的一致性可能会被破坏,所以类似ext4这样的文件系统需要复杂烧脑的日志机制,要协调这个metadata和data的同步,这个过程显然是很痛苦的。
John Gray和Prasad Singamsetty他们在Oracle的“block atomic writes”这一patchset[22]的目标是:提供一个接口,使应用程序能够使用应用特定的块大小,该块大小可以大于存储设备报告的逻辑块大小,或者大于通过 stat 获取的文件系统块大小。通过这个新接口,应用程序的blocks在写入时将不会被分裂,在发生断电的情况下,对于每个独立的应用程序块,要么所有数据都被写入,要么完全没有写入,不会出现部分写入的情况。用户态透过调用pwritev2的时候设置RWF_ATOMIC来告诉内核这个写请求是禁止torn-write 的,SCSI/NVMe都可能有硬件层面的原子写支持。硬件单元可以保证原子写的原子性,对于SCSI,John Gray的patch使能了WRITE_ATOMIC_16命令:
与SCSI不同,NVMe没有专门的原子写入命令,但是只要写入操作符合原子大小限制和边界规则,它就会被隐式地视为原子操作。所以NVMe重点是进行这个检查:
block层也会有些改动来表面block设备是否支持原子写,以及伴随的文件f_mode是否因而支持原子写:
前面的工作主要围绕应用程序DIRECT_IO的场景,John Gary的buffered block atomic writes这个patchset则瞄准buffered I/O的原子写支持,在iomap,xfs进行必要的改造[23]。sched_ext BPF调度的系列进展
sched_ext BPF调度在2024年全面开花结果,由Linus Torvalds拍板正式合入Linux mainline。特洛伊之战中两位伟大英雄阿喀琉斯和赫克托耳的决斗时刻,命运的天平最终向Tejun Heo倾斜,与赫克托结局不同的是,英雄的Peter Zijlstra仍然地战斗在EEVDF、PREEMPT_LAZY等领域,战无不胜。
这是sched_ext调度实例爆发的一年,在github.com/sched-ext/scx仓库中,提供了一系列BPF调度器,比如:
scx_lavd,强调交互性,特别是能够在游戏中持续实现更高的帧率;scx_lavd即将用于 Steam Deck 游戏系统中。
scx_bpfland, 旨在最大限度地减少响应时间;scx_bpfland 在个人计算机上表现出色。
scx_rustland,它只是将调度事件转发到用户空间,由用户空间进行决策;
由于BPF有和userspace交互的手段,这使得userspace调度成为可能。其工作流程是:
任务被添加到 BPF_MAP_TYPE_RINGBUF:被拦截的任务会被存入一种 BPF 的数据结构,即环形缓冲区(BPF_MAP_TYPE_RINGBUF),它是一种高效的数据传递机制。
BPF 组件调度用户空间任务:一个 BPF 程序负责唤醒用户空间的调度程序(scheduler)。这是一个自定义的用户空间调度器,用于处理任务分配。用户空间的调度器从 BPF_MAP_TYPE_RINGBUF 中读取任务,并根据特定的算法为每个任务分配 CPU 和时间片。
任务被添加到 BPF_MAP_TYPE_USER_RINGBUF:用户空间调度器处理完任务后,将其放入另一种环形缓冲区(BPF_MAP_TYPE_USER_RINGBUF),供后续处理。
BPF 组件从用户环形缓冲区中消费任务并分发:最后,BPF 组件从用户空间的环形缓冲区中读取任务并将其分发到指定的 CPU 运行。
基于上述原理的scx_rustland的架构图如下[24]:scx_rusty 用于在复杂的 cpu 拓扑结构上进行负载均衡;
scx_layered 是一种分区调度器。scx_layered 已部署在超过一百万台设备中,并带来了显著的性能提升。
多种发行版已开始支持sched_ext,包括CachyOS、Arch Linux、Ubuntu、 Fedora、Nix以及openSUSE。在这些发行版中,只需安装一个软件包并运行一个程序即可完成新调度器的部署。
Changwoo Min(changwoo@igalia.com)在lpc2024的slides - Using sched_ext to improve frame rates on the SteamDeck - Ideas behind the LAVD scheduler[25]很值得一读,它分析了游戏workload的特点。游戏工作负载的一个关键特点是任务运行时间通常很短,通常不超过 100µs。然而,这些任务之间往往高度关联,一些任务按照特定的“你唤醒我,我唤醒他,他再唤醒她……”的路径执行,这些路径sequence影响最终游戏体验,被称为关键路径(critical path)。
每个任务是否对延迟敏感由其在关键路径中的位置决定;那些需要等待其他任务完成并被其他任务依次等待的任务,对整体性能的影响较大,因此被称为“延迟关键(latency critical)”任务。
比如下面的任务:
在链条中间的那个任务既有很高的wake up 频率,又有很高的wait频率,可能就是关键中的关键了[26]:在具体的策略层面上,lavd采用了类似EEVDF的virtual Deadline优先的调度,支持基于延迟的调度。
此外,sched_lavd的工作还包含了对big.LITTLE大小核功耗性能地感知,提供Autopilot模式,根据system-wide的CPU利用率自动调整core选择策略。
最终实现framerate和功耗的双赢。
Nvidia的Andrea Righi也展示了他们基于scx_rustland的userspace调度器[24],保证了任何场景下游戏持续的60fps:无论游戏运行过程中其他任务的负载如何,都稳定提供60fps:
最后一个彩蛋: kernel panic二维码
我们在欢快的气氛中结束本文,内核panic的信息现在可以在屏幕上显示为一个二维码了。
这个工作drm/panic: Add a qr_code panic screen[27]由Jocelyn Falempe 完成,可以将kmsg信息嵌入QR-code中。看到这个二维码,立即产生了扫码付款的冲动,不过扫完了,出来的是一个内核panic的消息,惊不惊喜,意不意外?
亲爱的朋友们,今年就聊到这里,我们明年再会。让我们用最大的热忱,投入生活。假如生活欺骗了你, 不要悲伤,不要心急!忧郁的日子里须要镇静,因为Linux内核从不抛弃你,在你的手机里,在你的电脑里,在你周围的每一个可能的电子设备里,它将守护你的周全和快乐。
作者简介:
宋宝华,长期的一线 Linux 内核开发者,工作于内核调度器、内存管理、ARM/ARM64 arch、设备驱动等领域,向内核提交了数百个补丁;同时也是经典书籍《Linux 设备驱动开发详解》的作者。
参考文献
[1]https://www.colfax-intl.com/downloads/intel-achieving-optimal-perf-iu-ssds.pdf
[2]https://lore.kernel.org/all/20240822135018.1931258-1-kernel@pankajraghav.com/
[3]https://lore.kernel.org/all/20240823190545.979059-1-usamaarif642@gmail.com/
[4]https://lore.kernel.org/all/20241107011246.59137-1-21cnbao@gmail.com/
[5]https://lore.kernel.org/all/20240622071231.576056-2-21cnbao@gmail.com/T/#u
[6]https://lore.kernel.org/all/20240730-swap-allocator-v5-0-cb9c148b9297@kernel.org/
[7]https://lore.kernel.org/all/20240807215859.57491-3-21cnbao@gmail.com/
[8]https://lore.kernel.org/all/20241007074609.447006177@infradead.org/
[9]https://lore.kernel.org/all/20241216190451.1c61977c@mordecai.tesarici.cz/
[10]https://lore.kernel.org/all/20240727102732.960974693@infradead.org/
[11]
https://netdevconf.info/0x18/docs/netdev-0x18-paper33-talk-slides/Advancing TCP for AI.pdf
[12]https://lore.kernel.org/netdev/20240831004313.3713467-1-almasrymina@google.com/
[13]
https://lpc.events/event/18/contributions/1775/attachments/1602/3320/Memory Allocation Profiling deployment results and future improvements.pdf
[14]https://lore.kernel.org/all/20240321163705.3067592-1-surenb@google.com/
[15]https://lore.kernel.org/all/cover.1718090413.git.baolin.wang@linux.alibaba.com/
[16]https://lore.kernel.org/all/20240614015138.31461-1-ioworker0@gmail.com/
[17]https://lore.kernel.org/all/20250106031711.82855-1-21cnbao@gmail.com/
[18]https://lore.kernel.org/all/20240529082824.150954-1-21cnbao@gmail.com/
[19]https://lore.kernel.org/all/20240908232119.2157-1-21cnbao@gmail.com/
[20]https://lore.kernel.org/all/cover.1711683069.git.baolin.wang@linux.alibaba.com/
[21]https://lore.kernel.org/all/20241001053222.6944-1-kanchana.p.sridhar@intel.com/
[22]https://lwn.net/ml/linux-kernel/20240326133813.3224593-1-john.g.garry@oracle.com/
[23]https://lwn.net/ml/linux-kernel/20240422143923.3927601-1-john.g.garry@oracle.com/
[24]https://lpc.events/event/18/contributions/1723/attachments/1410/3430/crafting-user-space-scheduler-in-rust.pdf
[25]https://lpc.events/event/18/contributions/1713/attachments/1425/3058/scx_lavd-lpc-mc-24.pdf
[26]https://www.slideshare.net/slideshow/optimizing-scheduler-for-linux-gamingpdf/267643346
[27]https://lore.kernel.org/rust-for-linux/20240703154309.426867-1-jfalempe@redhat.com/
来源:CSDN