Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
RCU資料
Search
Yasuhiro Ohara
December 28, 2024
Programming
230
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
RCU資料
Yasuhiro Ohara
December 28, 2024
More Decks by Yasuhiro Ohara
See All by Yasuhiro Ohara
SRv6-mobile VPP plugin Performance Optimization
yasuhironet
2
730
sdplane wiretap 製品紹介
yasuhironet
0
52
Other Decks in Programming
See All in Programming
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
500
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
250
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
9
4.9k
Are APIs Still Relevant in the AI Era?
soyuka
0
290
Security issues being discussed on Web Platforms
petamoriken
0
1k
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
280
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.1k
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
200
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
370
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.7k
JPUG勉強会 OSSデータベースの内部構造を理解しよう(第2回)
oga5
0
270
Featured
See All Featured
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
410
Chasing Engaging Ingredients in Design
codingconduct
0
320
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
How to Talk to Developers About Accessibility
jct
2
550
The Cost Of JavaScript in 2023
addyosmani
55
10k
Music & Morning Musume
bryan
48
7.4k
Utilizing Notion as your number one productivity tool
mfonobong
4
590
The Limits of Empathy - UXLibs8
cassininazir
1
680
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Ethics towards AI in product and experience design
skipperchong
2
380
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
850
Transcript
RCU: Read-Copy-Update • マルチスレッドにおけるリーダーライターロックの代わり。 ロックレス • 参照するデータを変更の世代分⽤意して、すげ替える • 参照スレッド側で(スレッドローカル︖)コピーを持ってそれを読む から、Read-Copy
という名か︖すげ替える部分が Update︖ • QSBR がすごい • RCUには他にも memory barrier とか種類がある • QSBR: Quiescent State Based Reclamation • 多数の参照スレッド、少数(たぶん単⼀を想定)の更新スレッド • 参照スレッド側のオーバヘッドがほぼ皆無︕ • 本資料は QSBR に特化
RCU利⽤例︓⾼速DPDKルータ • RCU︓ロックを回避し、⾼速な同期処理する重要な技術 • DPDK pthreadがコアごとに独⽴して⾼速パケット処理、その間を RCU で調停 • RCUで共有するデータ︓経路表、ポート設定、ACLフィルター設定
DPDK P1 P4 P2 P3 CPU core1 CPU core2 CPU core3 CPU core4 OS l2fwd Forwarder P1/P2 l3fwd Forwarder P3/P4 lthread_main RCU • lthread_main: • startup_config • console_shell • tap_handler • stat_collector • l2fwd • (l3fwd-lpm)
操作関数 • rcu_assign_pointer()︓ • ポインタ登録。更新スレッドが使⽤。 • rcu_dereference()︓ • ポインタ取得。参照スレッドが毎回の read
critical section の先頭で使⽤。 • urcu_qsbr_quiescent_state()︓ • read critical section 外で、read critical section 外だということを、報告 する関数。参照スレッドが使⽤。 • urcu_qsbr_synchronize_rcu()︓ • 前スレッドが read critical section を⼀回以上抜けるまで待つ。更新スレッ ドが使⽤。この関数を呼び出し、帰って来れば、古い共有データのポインタ を保持している参照スレッドは居ないことが保証される。 • urcu_qsbr_register_thread()︓参照スレッド登録。 • urcu_qsbr_unregister_thread()︓参照スレッド登録の解除。
rcu-qsbr 更新スレッド 時間 データ 参照スレッド 参照スレッドのループの ⼀繰り返し期間は、 スレッド間でも、 スレッド内でも、 ⼀定ではない
参照スレッド 参照スレッド ループ quiescent_state() rcu_assign_pointer() read critical section synchronize_rcu() reclamation: 回収、再利⽤(削除) ⾚か⻘か不明な read critical section ⾚を保持する参照スレッドは居ない (だから消せる) read critical sectionは 毎回 rcu_dereference() し直して最新のポインタ取得 データ更新
Userscace RCU 実装内部 • カウンタを使ってスレッド間の緩い同期を図る • カウンタなのでほぼオーバヘッド無し • rcu_gp_ctr 変数(unsigned
long)。rcu_global_pointer_counter の略か。 • TLS(Thread-Local Storage)を使⽤。 • futex というカーネルサービスを使ってスレッドの WAKE/WAIT を実現 している • つまり、完全にユーザスペースで動くわけではなく、カーネル futex サービスを利 ⽤してユーザスペースでも機能する RCU ライブラリ、という位置付け。 • quiescent_state()︓ • rcu_gp_ctr を⾃スレッドローカルで更新し、そのカウンタ(カウント数)で待って るスレッドを futex で wakeup。 • rcu_synchronize()︓ • futex で全スレッドを待つ。
urcu-qsbr 使い⽅(更新スレッド) void *rcu_global_ptr_rib; void rib_replace () { #if HAVE_LIBURCU_QSBR
struct rib *new, *old; /* allocate new */ new = malloc (sizeof (struct rib)); /* retrieve old */ old = rcu_dereference (rcu_global_ptr_rib); if (old) memcpy (new, old, sizeof (struct rib)); /* update new */ rib_edit (new) ... /* assign new */ rcu_assign_pointer (rcu_global_ptr_rib, new); /* wait all readers to update. */ urcu_qsbr_synchronize_rcu (); /* reclaim old */ free (old); #endif /*HAVE_LIBURCU_QSBR*/ }
urcu-qsbr 使い⽅(参照スレッド)(1) #if HAVE_LIBURCU_QSBR urcu_qsbr_register_thread (); #endif /*HAVE_LIBURCU_QSBR*/ /* main
loop */ while (! force_quit && ! force_stop[lcore_id]) { #if HAVE_LIBURCU_QSBR urcu_qsbr_read_lock (); rib = (struct rib *) rcu_dereference (rcu_global_ptr_rib); #endif /*HAVE_LIBURCU_QSBR*/ パケット受信(); パケット処理(); #if HAVE_LIBURCU_QSBR urcu_qsbr_read_unlock (); urcu_qsbr_quiescent_state (); #endif /*HAVE_LIBURCU_QSBR*/ loop_counter++; } #if HAVE_LIBURCU_QSBR urcu_qsbr_unregister_thread (); #endif /*HAVE_LIBURCU_QSBR*/ } read critical section
urcu-qsbr 使い⽅(参照スレッド)(2) #if HAVE_LIBURCU_QSBR urcu_qsbr_register_thread (); #endif /*HAVE_LIBURCU_QSBR*/ /* main
loop */ while (! force_quit && ! force_stop[lcore_id]) { #if HAVE_LIBURCU_QSBR urcu_qsbr_read_lock (); rib = (struct rib *) rcu_dereference (rcu_global_ptr_rib); #endif /*HAVE_LIBURCU_QSBR*/ パケット受信(); パケット処理(); #if HAVE_LIBURCU_QSBR urcu_qsbr_read_unlock (); urcu_qsbr_quiescent_state (); #endif /*HAVE_LIBURCU_QSBR*/ loop_counter++; } #if HAVE_LIBURCU_QSBR urcu_qsbr_unregister_thread (); #endif /*HAVE_LIBURCU_QSBR*/ } read critical section read_lock(), read_unlock()は qsbr の場合は本当に何もしない、 呼ばなくても良い
urcu-qsbr 使い⽅(参照スレッド)(3) #if HAVE_LIBURCU_QSBR urcu_qsbr_register_thread (); #endif /*HAVE_LIBURCU_QSBR*/ /* main
loop */ while (! force_quit && ! force_stop[lcore_id]) { #if HAVE_LIBURCU_QSBR rib = (struct rib *) rcu_dereference (rcu_global_ptr_rib); #endif /*HAVE_LIBURCU_QSBR*/ パケット受信(); パケット処理(); #if HAVE_LIBURCU_QSBR urcu_qsbr_quiescent_state (); #endif /*HAVE_LIBURCU_QSBR*/ loop_counter++; } #if HAVE_LIBURCU_QSBR urcu_qsbr_unregister_thread (); #endif /*HAVE_LIBURCU_QSBR*/ } read critical section read_lock(), read_unlock()は qsbr の場合は本当に何もしない、 呼ばなくても良い
urcu-qsbr 使い⽅(まとめ) 更新スレッド︓ void *var; writer(){ void *old, *new; new
= create_new (); rcu_assign_pointer (var, new); synchronize_rcu (); free (old); } 参照スレッド︓ reader() { urcu_qsbr_register_thread (); while(1) { rcu_quiescent_state (); //rcu_read_lock(); p = rcu_dereference (var); ... //critical section using p. //rcu_read_unlock(); } urcu_qsbr_unregister_thread (); }
注意点︓ • 利⽤ユーザ側が⾃分で守らなければいけないルール︓ • read critical section の外から、中に⼊った時には、 rcu_dereference() し
て最新のポインタを取得することがルール。 • quiescent_state() の前後で、同じ古いポインタを維持・参照しないこと。 rcu_dereference() し直すこと。 • 参照スレッドは全て登録(register_thread())すること。 • ⾃由度︓ • ⼀ループ繰り返しの中では、read critical section の外であれば、 quiescent_state() は前でも後ろでも良い。呼び出し(報告)場所はどこで も⼤丈夫。(毎回rcu_dereference()していれば、)read critical section が細切れにたくさんあって、その途中のどこかでも⼤丈夫。複数回呼んでも ⼤丈夫。 • 更新スレッド⾃⾝を参照スレッド登録するのはちょっと複雑で危険。 デッドロックっぽいスレッド停⽌が起きた。
ポート設定コンフリクト • ポート設定をrcu変更すると き、スレッド間でタイミング 合わない(同期しない)と、 同じポート(queue)にアク セスして、クラッシュする t1 t2 p0
p1 thread: t1 port: 0 thread: t2 port: 1 thread: t1 port: 0 thread: t1 port: 1 rcu x
ポート設定コンフリクトの解消 • rcuで、コンフリクトが解消 できるような中間状態の設定 を追加することで、スレッド 間の同期も実現できる • (差分計算が⾯倒くさければ、 緑の中間状態を空にしてしま えば、効率性・性能を犠牲に
して安全性を獲得できる) t1 t2 p0 p1 thread: t1 port: 0 thread: t2 port: 1 thread: t1 port: 0 rcu t1 t2 p0 p1 thread: t1 port: 0 thread: t1 port: 0 thread: t1 port: 1 rcu