---
tags: rcu, NOTES
---
# So What Has RCU Done Lately? (2023)
> [youtube](https://youtu.be/9rNVyyPjoC4)
> [slides](https://drive.google.com/file/d/19Oa5phwRImKr4sUirjYxc8oOi0lKHxVL/view)
## 心得
這場演講告訴大家最近 Read-copy-update (RCU) 有哪些變化,改變的原因是什麼,以及未來的發展方向又有哪些。講到了不同 RCU variant 與 API 在實際使用後所面臨的問題與反饋,開發團隊也因應各種問題提出了些解決方法或是權宜之計。
雖然 RCU 的概念很簡單 (RCU is dead simple),但融入 Linux 核心後,不免俗得顧及到很多面向。簡單的概念在經歷了現實考量後,衍生出各式各樣又複雜的 variant,要面面俱到實在不容易。我想這也是為什麼 RCU 早在 2002 年就加入 Linux 核心,卻直到現在仍在開發中 (under development)
- Backporting 到舊版時會不會出錯
- 在 32-bit system 時可能遭遇 overflow
- 從 Embedded system 到 High performance computing 的使用情境都得考慮
- 與 Lockdep, BPF trampoline 等機制如何並存
- 在 real-time 的環境下如何正確運行又不過度影響其餘 task
- 在 mobile device (ChromeOS, Android) 上需要顧及 battery lifetime
- 處理 RCU Callback 也要顧及 cache locality (e.g. [RCU Callback Handling](https://www.kernel.org/doc/html/v5.5/RCU/Design/Data-Structures/Data-Structures.html#rcu-callback-handling))
:::success
前情提要,什麼是 Read-copy-update (RCU)
- [Linux 核心設計: RCU 同步機制](https://hackmd.io/@sysprog/linux-rcu)
- [What is RCU? – "Read, Copy, Update"](https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html)
- [What is RCU, Fundamentally?](https://lwn.net/Articles/262464/)
:::
---
## 開場
![](https://i.imgur.com/sCCUNbM.png)
RCU 還在開發中嗎 (under active development)? 當然
spinlock 跟 atomic operations 同樣也還在開發中
---
## 經典 RCU review
Paul 幾乎每次演講都會講一次這些XD
![](https://i.imgur.com/j5LXxVm.png)
右下角是不該出現的情況,有潛在的 use after free 風險
`synchronize_rcu()` 理應避免這情況出現
----
### Code Animation (印象中 animation 在其他演講,這裡沒展示)
![](https://i.imgur.com/0ubObiB.png)
左右都是 reader, 中間是 updater。
雖然 updater 將資料從 blue node 更新到 green node,但左邊的 reader 讀取到的仍是 obsolete data,也就是 blue node。
Paul 說 RCU 的 lack of synchronize 就像我們透過電腦接觸世界,圖中的紅線以上就像是我們透過電腦得到世界上的資訊,但世界無時無刻都在改變。
----
### Core APIs
![](https://i.imgur.com/00THqk8.png)
----
### RCU compared to rwlock
![](https://i.imgur.com/Rj2B0XD.png)
Get much more efficient usage of CPU
- red part: CPU delay
----
### RCU compared to rwlock: Scalability (Empty critical section)
![](https://i.imgur.com/LYIrGGY.png)
- y-axis: ns per operation (越低越好)
- x-axis: number of CPUs
----
### RCU compared to rwlock: Scalability (Non-Empty critical section)
![](https://i.imgur.com/RSARO2i.png)
- y-axis: ns per operation (越低越好)
- x-axis: critical section duration (ns)
#### In short:
如果 CPU 數量很少,且 critical section 很大,那 rwlock 對你來說就夠了
但如果 CPU 數量很多,且 critical section 很短 (protecting a very fast data structure like hash table),那 RCU 可以帶來巨大的 benefits
----
### Restrictions
![](https://i.imgur.com/IiEI6bc.png)
==RCU is a specialized tool==
----
### Use cases
![](https://i.imgur.com/N4SKcHj.png)
RCU 比起其他方法簡單,使用的地方更多
---
## RCU Changes
### Outline (這裡只快速帶過,因為每個 topic 都可以當一個 full presentation)
![](https://i.imgur.com/P92GE5f.png)
----
### Flavor consolidation
在 2019 改的,因為原先得設計較為複雜 (原本 RCU 不同 flavor 的 reader 需要對應不同 flavor 的 synchronize_rcu),而開發者使用錯誤時會造成 exploit (security issue),所以將其整合簡化
- 錯誤的使用造成 exploit
![](https://i.imgur.com/IyKhZR7.png =600x)
- before
![](https://i.imgur.com/Jl5MzFK.png =600x)
- after
![](https://i.imgur.com/kP0wXKd.png =600x)
#### Backport
![](https://i.imgur.com/BJTeJP4.png =600x)
backport 到 v4.19 或更早的版本會需要做更改,請使用 `synchronize_rcu_mult()` (mult: multiple)
:::success
- [RCU flavor consolidation](https://lwn.net/Articles/777036/#Summary%20of%20RCU%20API%20Changes)
:::
----
### Optional Lockdep expression
![](https://i.imgur.com/prtCkM8.png =600x)
提升與 Lockdep 的整合
告訴 lockdep 不論是當個 RCU reader 或拿了 lock,either way is fine,別報 warning
(it allows shared code to work better)
\>> Get good debug ability without API explosion
:::success
What is lockdep?
- [Interrupts, threads, and lockdep](https://lwn.net/Articles/321663/)
- [Runtime locking correctness validator](https://docs.kernel.org/locking/lockdep-design.html)
- [Lockdep-RCU](https://lwn.net/Articles/371986/)
- [The kernel lock validator](https://lwn.net/Articles/185666/)
:::
----
### Single-argument kfree_rcu() and kvfree_rcu()
1. 原版的 `kvfree_rcu()` 有兩個參數,第二個參數是 name of rcu_head。
2. 雖然使用起來沒問題,但如果在很小的 structure 上且在 kernel 內的數量非常大時,額外的 8 byte (64-bit system) 會變成問題。
所以新版的 `kvfree_rcu()` 拿掉了第二個參數,改善了上述的問題,但 trade-off 是變成用 allocate memory 的方式來做 track,在遇到 out of memory 時會進入 sleep,可能產生額外的 latency。
![](https://i.imgur.com/jxJUpdU.png)
3. 又因為 single argument `kvfree_rcu()` 可能會進入 sleep,即便環境允許,但額外的 sleep 可能造成 SLA 上的困擾或是 lockdep 的 warning。所以後續重新命名,新增 suffix 變成 `kvfree_rcu_mightsleep()`。讓開發者能 ease of use 但需要打更多字XD
(既能避免開發者誤用 single argument `kvfree_rcu()` ,也把 atomic contexts 與 non-atomic contexts 切開)
![](https://i.imgur.com/FiIyY69.png)
:::success
- `kfree_rcu()`: If the callback for call_rcu() is not doing anything more than calling kfree() on the structure, you can use kfree_rcu() instead of call_rcu() to avoid having to write your own callback:
> reference from [What is RCU? – “Read, Copy, Update”](https://www.kernel.org/doc/html/latest/RCU/whatisRCU.html)
- [rcu: introduce kfree_rcu()](https://lwn.net/Articles/433493/)
- source code: [#define kvfree_rcu(...)](https://elixir.bootlin.com/linux/v6.2.11/source/include/linux/rcupdate.h#L1013)
- Rename kvfree_rcu() to kvfree_rcu_mightsleep(): The goal is to avoid accidental use of the single-argument forms, which can introduce functionality bugs in atomic contexts and latency bugs in non-atomic contexts.
> reference from [Re: [PATCH v2 01/14] drbd: Rename kvfree_rcu() to kvfree_rcu_mightsleep()](https://lore.kernel.org/lkml/e5b78f91-122a-0b0d-8d3f-922d462ba44d@kernel.dk/)
:::
----
### Polled Grace-Period APIs
1. 原版 polled grace-period API 的使用流程
得到 cookie 後,可以先 do sth,再透過 `cond_synchronize_rcu` 確認 cookie,就可以知道 grace period 是否已經完成。還沒完成的話可以透過 `synchronize_rcu()` 等待到完成
(if you do sth takes a while, you get safety but no extra overhead)
![](https://i.imgur.com/tQy2Dq4.png)
2. 新版 polled grace-period API 的使用流程
![](https://i.imgur.com/ZLzEZRI.png)
![](https://i.imgur.com/60FPyrb.png)
原版的 API 有潛在的問題會造成 `synchronize_rcu()` 得到 false positive:
1. counter wrap: limit counter bit 造成 overflow (在 32-bit system 時較容易發生)
透過使用 `get_completed_synchronize_rcu()` 解決
2. 但即便使用 `get_completed_synchronize_rcu()`,若遇到 normal/expedited `synchronize_rcu()` 有 overlapping 發生時,也會造成 normal / expedited 競爭 state variable (cookie) 的問題 (或是用兩個 `synchronize_rcu()` 來解決,因為總有一個會搶贏XD)
$\to$ 透過使用 \_full suffix API 處理,此 API 會有兩個 counter 給不同的版本使用,讓兩者分開避免發生競爭
==Lockless grace period API==
:::success
- [[PATCH rcu 01/12] rcu: Make normal polling GP be more precise about sequence numbers](https://lore.kernel.org/lkml/20220722010341.GC1790663@paulmck-ThinkPad-P17-Gen-1/T/)
- [get_completed_synchronize_rcu_full()](https://elixir.bootlin.com/linux/v6.2.11/source/kernel/rcu/tree.c#L3579)
- [struct rcu_gp_oldstate](https://elixir.bootlin.com/linux/v6.2.11/source/include/linux/rcutree.h#L44)
:::
----
### Tasks Trace RCU and Tasks Rude RCU
![](https://i.imgur.com/0sHWpJO.png)
For tracing and BPF
----
### Runtime RCU Callback (De-)Offlodaing
1. 在沒有 callback offloading 時,invoke callback 時會產生 interrupt,即便是 high priority 的工作也會被打斷。對 real-time 的情境不好
![](https://i.imgur.com/02Q4Xvs.png)
2. 引入 callback offloading 之後,將 callback 交給專門的 rcuo kthread 來做,此時他會是一個 normal task,可以放入 scheduler 中排程,不打斷 high priority tasks
(也可以 reduce jitter & save power)
![](https://i.imgur.com/tp8KsTy.png)
3. 但因為原本的 callback offloading 需要在 boot time 就決定好哪些 CPU 要 offloading 哪些不要,不彈性且麻煩,所以接著改進成可以有限度的在 runtime 進行調整,決定此 cpu 是否要做 offloading
![](https://i.imgur.com/ah3EMnf.png)
:::success
- [rcu/nocb: De-offload and re-offload support v3](https://lwn.net/Articles/835039/)
:::
----
### SRCU memory-footprint diet
1. 最早的 srcu_struct 小小的 (hundreds of Bytes),但只有一個 callback list,會造成 global contention
2. v4.12 後新增的 srcu_node,透過 combining tree 的結構,即便在大量的 CPU 下也能控制住 lock contention 的程度。
3. 隨之產生的問題是這必須在 build time 就配置好,並且此時只知道 CPU 的數量。而有些 distros 的 NR_CPUS 可以多達 4096,雖然 26KB 對一台 big machine 不是什麼負擔。但有些人會將 srcu structs 放在其他 structures 中,此時卻會因為結構太大,不能透過短短的 assembly 馬上得到 offset,進而讓 compiler 產生 worse code。
![](https://i.imgur.com/SPtfXgG.png)
4. 最新的方式是將 `srcu_struct` 與 `srcu_node` 分開,選擇性的配置。現階段預設是在 < 128 CPUS 時不會配置 `srcu_node`
![](https://i.imgur.com/8FLVhxB.png)
5. 可以透過調整參數自行決定轉換的時機點
![](https://i.imgur.com/7RMY1yM.png)
==memory is cheap, but not that cheap==
----
### Real-time expedited grace periods
![](https://i.imgur.com/4bw5azw.png)
----
### Lazy RCU Callbacks
在 near-idle device 下,例如說使用者只是打開檔案,關掉,打開,關掉,重複很多次
產生出一堆 grace period 會造成沒必要的電量消耗,所以在 v6.2 誕生了 lazy grace period
\>> laziness can be a virtue
![](https://i.imgur.com/cxqh5se.png)
![](https://i.imgur.com/20fVYfH.png)
:::success
- [Linux 6.2 Likely To Enjoy Measurable Power-Savings While Idle Or Lightly Loaded](https://www.phoronix.com/news/Lazy-RCU-Likely-For-Linux-6.2)
:::
---
## Miscellaneous
![](https://i.imgur.com/X4YKgnl.png)
---
## Future
![](https://i.imgur.com/4Bl8Nd9.png)
---
## Trends
- upper line: RCU commit 數量
- lower line: 非 pual 的 RCU commit 數量
![](https://i.imgur.com/3pRdYXO.png)
* paul 所佔的 RCU commit 比例
![](https://i.imgur.com/8r5Oz84.png)
- 之前的演講也有提過,期許 RCU 的社群更加茁壯
![](https://i.imgur.com/m8HwJmh.png)
----
### Summary
![](https://i.imgur.com/5wFfYUq.png)
最後也是最重要的,RCU 仍在開發中,根據現在, 過去, 與未來的使用者需求,持續演化
:::success
- [Recent RCU changes](https://lwn.net/Articles/894379/)
- [Paul E. McKenney's Journal](https://paulmck.livejournal.com/)
- [[PATCH 1/1] Reduce synchronize_rcu() waiting time](https://lore.kernel.org/lkml/20230321102748.127923-1-urezki@gmail.com/)
:::