linux内核的tiny rcu, tree rcu

kernel中有两个rcu的实现,一个是tiny rcu,另一个是tree rcu。这两种rcu的前身都是classic rcu。
如果要阅读classic rcu的实现代码,必须找kernel 2.6.26,因为在kernel 2.6.27,classic rcu开始转型为使用tree node的scalable classic rcu,是现在的tree rcu趋形。
那么tiny rcu与classic rcu又是什么关系呢,tiny如其名,就是紧凑的classic rcu,专门为单cpu(uniproceesor)的嵌入系统(内存十分有限)而设计的。换句话说,相当于classic rcu的删减版。

classic rcu使用全局状态rcu_ctrblk,提供两个flaver的全局状态rcu_sched_ctrblk和rcu_bh_ctrblk。
tiny rcu沿用这两个全局状态,并将SMP部分的内容删减。
tree rcu则是将rcu_ctrblk演进成分层(hierarchical)结构,也就是树形。全局状态rcu_state,分层(树型)节点rcu_node,cpu独立状态rcu_data,以及cpu空闲变频状态rcu_dynticks。将原本在rcu_ctrblk的cpumask,以分层的方式分置到rcu_node的qsmask。

现在tree rcu包含了许多特性,初涉者不容易在庞大的结构体成员和众多特性功能的函数逻辑中分离出,与设计文档描述相吻合的(纯净或原始的)路径进行研究。
设计文档中描述了classic rcu就是kernel 2.6.16为止的rcu实现,而tree rcu的趋形就是从kernel 2.6.17开始。如果你对现在的kernel中的rcu实现感到迷惑的话,可以选择上面提到的两个版本的kernel的rcu进行比较来研究。
或者你可以参考第一份scalable classic rcu提交的日志文档,在LWN网站。文档以git diff的方式,更好地展现了classic rcu如何向tree rcu演进。
但是你不可能很好地从tiny rcu去研究classic rcu,虽然说tiny rcu是classic rcu的精简,但是已经将SMP部分实现基本去除(比如qsmask),而tree rcu和classic rcu同是基于SMP的实现。
因此如果你将tiny rcu作为classic rcu去同tree rcu进行比较时,你会根本找不到SMP相关部分的影子,差异巨大而找不出演进的连接点(相关性),从而迷惑。

classic rcu的rcu_ctrblk中有我们熟知的rcu文档描述的qsmask,用于维护(或感知)一个gp。而tree rcu则是将这个qsmask进行分层,tiny rcu却是将这个qsmask丢弃。如果你不清楚这一点,当你比较tree rcu和tiny rcu时,中间就会有断层,联系不上。
这是因为tiny rcu限定了单CPU(uniprocessor)的条件。在tiny rcu实现中并没有任何per cpu变量。并且在cpu提交一次qs的同时,就会发起rcu softirq,换句话说,gp并没有另外进行维护管理,只是简单地将gp等同于每次qs的提交。

classic rcu和tree rcu同样都使用nxtlist和nxttail来维护4段rcu callbacks的 batch处理。而tiny rcu将其精简为rcucblist,以及donetail和curtail这样形式的2段rcu batch,并且简化当中的维护。
当使用者调用synchronize_sched或call_rcu时,同步(或者说是延后)的回调就会链到cur段。当调度器scheduler提交一次qs时,就会将cur段的回调纳入done段,并发起rcu softirq。当内核kernel处理rcu softirq就会从done段将回调batch处理。
由此我们不容易发现tiny rcu在维护gp和qs。

tiny rcu和tree rcu是classic rcu不同方向的结果,tiny rcu为uniprocessor且资源有限的嵌入场合而去简化(剦切)了classic rcu,另外tree rcu则是使classic rcu向前朝超级多cpu(在rcu文档中,a few of hundren表示数百cpu还不值一提,起码也要成千上万,当时2008年)的场合,演进更高效更稳定。
kernel 2.6.27是分水岭,classic rcu向tree rcu演进。tiny rcu和tree rcu同是2008年的产物。
在kconfig中,tree rcu是默认的rcu。如果需要preempt rcu的话,必须使用tree rcu。换句话说,tiny rcu不支持preempt rcu。

scalable classic RCU implementation》kernel 2.6.27 第一份基于tree node分层的classic rcu代码提交日志文档。

Hierarchical RCU

RCU: The Bloatwatch Edition》tiny rcu的设计文档。

Simplifying RCU》kernel 3.11 移去CONFIG_PREEMPT_TINY,即移去preempt tiny rcu。

时间: 2024-10-14 00:10:57

linux内核的tiny rcu, tree rcu的相关文章

大话Linux内核中锁机制之RCU、大内核锁

大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linux内核中锁机制>系列博文进行了总结,并提出关于目前Linux内核中提供的锁机制的一些基本使用观点. 十.RCU机制 本节将讨论另一种重要锁机制:RCU锁机制.首先我们从概念上理解下什么叫RCU,其中读(Read):读者不需要获得任何锁就可访问RCU保护的临界

linux 内核 RCU机制详解

RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制读取数据的时候不对链表进行耗时的加锁操作.这样在同一时间可以有多个线程同时读取该链表,并且允许一个线程对链表进行修改(修改的时候,需要加锁).RCU适用于需要频繁的读取数据,而相应修改数据并不多的情景,例如在文件系统中,经常需要查找定位目录,而对目录的修改相对来说并不多,这就是RCU发挥作用的最佳场景.

大话Linux内核中锁机制之完成量、互斥量

大话Linux内核中锁机制之完成量.互斥量 在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等待另一个执行单元完成某事后方可执行,它是一种轻量级机制.事实上,它即是为了完成进程间的同步而设计的,故而仅仅提供了代替同步信号量的一种解决方法,初值被初始化为0.它在include\linux\completion.h定义. 如图8.1所示,对于执行单元A

Linux内核RCU(Read Copy Update)锁简析

在非常早曾经,大概是2009年的时候.写过一篇关于Linux RCU锁的文章<RCU锁在linux内核的演变>,如今我承认.那个时候我尽管懂了RCU锁,可是我没有能力用一种非常easy的描写叙述把Linux的实现给展示出来,有道是你能给别人用你自己的方式非常简洁地描写叙述清楚,你才是真正的精通它.否则,无异于背诵.换个说法,假设你在被面试.在短时间内靠嘴说给面试官,且他还要能听明白,就说明自己真的懂了,这样的时候,是不会给你机会分析源码的,也不可能让你背诵源码.       时隔五年多,最近又

Linux内核同步 - classic RCU的实现

一.前言 无论你愿意或者不愿意,linux kernel的版本总是不断的向前推进,做为一个热衷于专研内核的工程师,最大的痛苦莫过于此:当你熟悉了一个版本的内核之后,内核已经推进到一个新的版本,你曾经熟悉的内容可能会变得陌生(这里主要说的是该模块的内部实现,实际上,内核中的每一个子系统都是会尽量保持接口API的不变).怎么应对这种变化呢?一方面,具体的实现可能千差万别,但是基本的概念是一样的,无论哪一个版本的内核,总是能够理解一个内核子系统的基本概念和运作机理.另外一方面,不同版本之间的实现不同往

再谈Linux内核中的RCU机制

转自:http://blog.chinaunix.net/uid-23769728-id-3080134.html RCU的设计思想比较明确,通过新老指针替换的方式来实现免锁方式的共享保护.但是具体到代码的层面,理解起来多少还是会有些困难.在<深入Linux设备驱动程序内核机制>第4章中,已经非常明确地叙述了RCU背后所遵循的规则,这些规则是从一个比较高的视角来看,因为我觉得过多的代码分析反而容易让读者在细节上迷失方向.最近拿到书后,我又重头仔细看了RCU部分的文字,觉得还应该补充一点点内容,

Linux内核Radix Tree(二)

1.   并发技术 由于需要页高速缓存是全局的,各进程不停的访问,必须要考虑其并发性能,单纯的对一棵树使用锁导致的大量争用是不能满足速度需要的,Linux中是在遍历树的时候采用一种RCU技术,来实现同步并发. RCU(Read-Copy Update),是一种保证读该radix tree的时候,可以不要管insert/delete操作,即不需使用锁.从内核代码来看,lookup操作的时候,读一个节点的时候,采用类似于 node = rcu_dereference(*slot); 的调用.Inse

内核中的锁机制--RCU

一. 引言 众所周知,为了保护共享数据,需要一些同步机制,如自旋锁(spinlock),读写锁(rwlock),它们使用起来非常简单,而且是一种很有效的同步机制,在UNIX系统和Linux系统中得到了广泛的使用.但是随着计算机硬件的快速发展,获得这种锁的开销相对于CPU的速度在成倍地增加,原因很简单,CPU的速度与访问内存的速度差距越来越大,而这种锁使用了原子操作指令,它需要原子地访问内存,也就说获得锁的开销与访存速度相关,另外在大部分非x86架构上获取锁使用了内存栅(Memory Barrie

Linux内核Radix Tree(一)

一.概述 Linux radix树最广泛的用途是用于内存管理,结构address_space通过radix树跟踪绑定到地址映射上的核心页,该radix树允许内存管理代码快速查找标识为dirty或writeback的页.Linux radix树的API函数在lib/radix-tree.c中实现. Linux基数树(radix tree)是将指针与long整数键值相关联的机制,它存储有效率,并且可快速查询,用于指针与整数值的映射(如:IDR机制).内存管理等. 上图显示了一个有3级结点的radix