RCU CPU STALL DETECTOR

本文深入解析Linux内核中的RCU(Read-Copy-Update)机制,介绍其工作原理、应用场景及如何通过RCU CPU Stall Detector诊断RCU stall警告。

在RHEL 7 和 SELS11 SP2 之后的Linux系统上,有时会看到如下信息:

INFO: rcu_sched_state detected stall on CPU 5 (t=2500 jiffies)
INFO: rcu_bh_state detected stalls on CPUs/tasks: { 3 5 } (detected by 2, 2502 jiffies)

它们来自RCU CPU Stall Detector,要了解RCU CPU Stall Detector是什么,首先要知道RCU是什么。RCU(Read-Copy Update) 是Linux 2.6 内核开始引入的一种新的锁机制,与spinlock、rwlock不同,RCU有其独到之处,它只适用于读多写少的情况。

RCU是基于其原理命名的,Read-Copy Update,[Read]指的是对于被RCU保护的共享数据,reader可以直接访问,不需要获得任何锁;[Copy Update]指的是writer修改数据前首先拷贝一个副本,然后在副本上进行修改,修改完毕后向reclaimer(垃圾回收器)注册一个回调函数(callback),在适当的时机完成真正的修改操作–把原数据的指针重新指向新的被修改的数据,–这里所说的适当的时机就是当既有的reader全都退出临界区的时候,而等待恰当时机的过程被称为grace period 。在RCU机制中,writer不需要和reader竞争任何锁,只在有多个writer的情况下它们之间需要某种锁进行同步作,如果写操作频繁的话RCU的性能会严重下降,所以RCU只适用于读多写少的情况。

RCU API 最核心的函数是: 
rcu_read_lock() 
rcu_read_unlock() 
synchronize_rcu() 
call_rcu()

  • rcu_read_lock()和rcu_read_unlock()配对使用,由reader调用,用以标记reader进入/退出临界区。夹在这两个函数之间的代码区称为”读端临界区”(read-side critical section),注:读端临界区可以嵌套。reader在临界区内是不能被阻塞的。
  • synchronize_rcu()由writer调用,它会阻塞writer(即writer会进入睡眠等待),直到经过grace period后,即所有的reader都退出读端临界区,writer才可以继续下一步操作。如果有多个writer调用该函数,它们将在grace period之后全部被唤醒。
  • call_rcu()是synchronize_rcu()的非阻塞版本,它也由 writer调用,但不会阻塞writer(即writer不会进入睡眠,而是继续运行),因而可以在中断上下文或 softirq 中使用,而 synchronize_rcu()只能在进程上下文使用。call_rcu()把参数中指定的callback函数挂接到 RCU回调函数链上,然后立即返回。一旦所有的 CPU 都已经完成端临界区操作(即grace period之后),该callback函数将被调用,用writer修改过的数据副本替换原数据并释放原数据空间。需要指出的是,函数 synchronize_rcu 的实现实际上也使用了函数call_rcu()。

RCU API 有一些特殊用途的分支,比如 RCU BH (防DDoS攻击的API)、 RCU Sched (适用于 scheduler 和 interrupt/NMI-handler 的 API),等。参见 http://lwn.net/Articles/264090/

RCU在Linux 2.6内核中(RHEL6和SLES11 SP1)就已经存在了,那时处理 grace period 利用了软中断(softirq),而到了新的3.x内核之后有所改变,处理grace period利用的是内核线程,因为内核线程可以被抢占,减少了实时任务的响应延迟。所以在3.x内核的系统上,会看到类似如下的内核线程: 
[rcu_sched] 
[rcu_bh] 
[rcuob/0] 
[rcuob/1] 
[rcuos/0] 
[rcuos/1] 
还有可能会见到rcu_preempt线程。 
注:其中 rcuob/N, rcuos/N 是负责处理 RCU callbacks 的内核线程,参见https://www.kernel.org/doc/Documentation/kernel-per-CPU-kthreads.txt 

好了,现在终于可以讲 RCU CPU Stall Detector 了,它其实是RCU代码中的一个debugging feature(参见https://lwn.net/Articles/301910/ ),在2.6内核中缺省是关闭的,而到3.x内核中缺省是打开的,它有助于检测导致 grace period 过度延迟的因素,因为grace period的长短是RCU性能的重要因素。发生RCU grace period延迟会在系统日志中记录告警信息,称为 RCU CPU Stall Warnings 

INFO: rcu_sched_state detected stalls on CPUs/tasks: { 15} (detected by 17, t=15002 jiffies) 
或 
INFO: rcu_bh_state detected stalls on CPUs/tasks: { 3 5 } (detected by 2, 2502 jiffies) 
等等。

在上述告警信息之后通常还会看到相关CPU的stack dump,检查stack trace有助于了解当时运行的代码和可能导致延迟的原因。

如果你不想看到以上告警信息,可以通过以下参数关掉它: 
/sys/module/rcupdate/parameters/rcu_cpu_stall_suppress 
注:缺省值为0,表示显示延迟告警;置为1表示禁止显示延迟告警。 
RCU grace period延迟多长时间会触发告警呢?这是以下参数决定的(以秒为单位): 
/sys/module/rcupdate/parameters/rcu_cpu_stall_timeout 
RCU的其它内核参数,如rcupdate.rcu_task_stall_timeout等参见: 
https://www.kernel.org/doc/Documentation/kernel-parameters.txt

有哪些原因会导致 RCU grace period延迟(RCU CPU Stall Warnings)呢?参见https://www.kernel.org/doc/Documentation/RCU/stallwarn.txt 这里仅列举几例:

  • CPU 在 RCU read-side 临界区内死循环
  • CPU 在屏蔽中断的情况下死循环
  • Linux引导过程中输出信息很多,但是所用的 console太慢,跟不上信息输出的速度。
  • 任何可能导致 RCU grace-period 内核线程无法运行的因素
  • 优先级很高的实时任务占着 CPU 不放,抢占了恰好处于RCU read-side临界区的低优先级任务。
  • RCU代码bug。
  • 硬件故障。.
  • 等等。

具体分析还需从告警信息中输出的stack trace入手。

参考资料: 
源代码:kernel/rcupdate.c, kernel/rcutree.c … 
https://www.ibm.com/developerworks/cn/linux/l-rcu/ 
https://www.kernel.org/doc/Documentation/RCU/stallwarn.txt 
https://www.kernel.org/doc/Documentation/RCU/whatisRCU.txt 
http://lwn.net/Articles/262464/ 
https://lwn.net/Articles/518953/

Using RCU's CPU Stall Detector 2 3 This document first discusses what sorts of issues RCU's CPU stall 4 detector can locate, and then discusses kernel parameters and Kconfig 5 options that can be used to fine-tune the detector's operation. Finally, 6 this document explains the stall detector's "splat" format. 7 8 9 What Causes RCU CPU Stall Warnings? 10 11 So your kernel printed an RCU CPU stall warning. The next question is 12 "What caused it?" The following problems can result in RCU CPU stall 13 warnings: 14 15 o A CPU looping in an RCU read-side critical section. 16 17 o A CPU looping with interrupts disabled. 18 19 o A CPU looping with preemption disabled. 20 21 o A CPU looping with bottom halves disabled. 22 23 o For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel 24 without invoking schedule(). If the looping in the kernel is 25 really expected and desirable behavior, you might need to add 26 some calls to cond_resched(). 27 28 o Booting Linux using a console connection that is too slow to 29 keep up with the boot-time console-message rate. For example, 30 a 115Kbaud serial console can be -way- too slow to keep up 31 with boot-time message rates, and will frequently result in 32 RCU CPU stall warning messages. Especially if you have added 33 debug printk()s. 34 35 o Anything that prevents RCU's grace-period kthreads from running. 36 This can result in the "All QSes seen" console-log message. 37 This message will include information on when the kthread last 38 ran and how often it should be expected to run. It can also 39 result in the "rcu_.*kthread starved for" console-log message, 40 which will include additional debugging information. 41 42 o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might 43 happen to preempt a low-priority task in the middle of an RCU 44 read-side critical section. This is especially damaging if 45 that low-priority task is not permitted to run on any other CPU, 46 in which case the next RCU grace period can never complete, which 47 will eventually cause the system to run out of memory and hang. 48 While the system is in the process of running itself out of 翻译上面文档
最新发布
10-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值