この記事はLinux Advent Calendar 2015の12月7日分です。
はじめに
LinuxのRCUを読んでみる (synchronize_rcu / call_rcu簡易版編)の続きというか番外編です。RCU関連のカーネルコンフィグオプションを調べていきます。今回はコードの解説はありません。
私がVMにセットアップしているFedora 21のカーネルなので、今回は4.0ベースです。4.3とそんなに変わらないと思います。
Fedora 21のカーネルコンフィグオプションを調べる
以下はFedora 21のRCU関連のカーネルコンフィグオプションです。
$ grep RCU /boot/config-4.0.4-202.fc21.x86_64
# RCU Subsystem
CONFIG_TREE_RCU=y
CONFIG_SRCU=y
# CONFIG_TASKS_RCU is not set
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_USER_QS=y
CONFIG_RCU_FANOUT=64
CONFIG_RCU_FANOUT_LEAF=16
# CONFIG_RCU_FANOUT_EXACT is not set
CONFIG_RCU_FAST_NO_HZ=y
# CONFIG_TREE_RCU_TRACE is not set
CONFIG_RCU_KTHREAD_PRIO=0
CONFIG_RCU_NOCB_CPU=y
# CONFIG_RCU_NOCB_CPU_NONE is not set
# CONFIG_RCU_NOCB_CPU_ZERO is not set
CONFIG_RCU_NOCB_CPU_ALL=y
# RCU Debugging
CONFIG_SPARSE_RCU_POINTER=y
CONFIG_RCU_TORTURE_TEST=m
CONFIG_RCU_CPU_STALL_TIMEOUT=60
# CONFIG_RCU_CPU_STALL_INFO is not set
# CONFIG_RCU_TRACE is not set
このコンフィグオプションが何なのか調べていきます。すべてのコンフィグオプションを網羅はしません。いずれはやりたいですが。
CONFIG_TREE_RCU
このコンフィグオプションがyの場合は、Hierarchical RCUという実装を使うようになります。これはwriter側のデータ構造を階層構造にすることで、writerのロック競合を減らす目的で設計されました。
それ以外の実装といえば、前回の記事で取り上げたユニプロセッサ版になります。
CONFIG_SRCU
SRCUとはSleepable RCUのことです。RCUは元々readerのクリティカルセクションでスリープしないという制約の元にwriter側がreaderの動作を妨げることなく待ち合わせを行なっていました。SRCUではこの制約を取り去り、readerのクリティカルセクションでスリープ可能にした実装です。どうやって実現しているのか、いずれ調べてみたいです。
CONFIG_TASKS_RCU
これはタスクの状態変化のみを待ち合わせの契機とする特殊な実装を有効にするか否かのオプションです。CPU横取りを契機とせず、自発的なコンテキストスイッチ、idle状態、ユーザプロセス実行のみを契機とすることで、実装を簡素化する(代わりに待ち合わせは遅くなる)ためのもののようです。これもいずれ調べてみたいです。
CONFIG_RCU_STALL_COMMON
ストール(RCUの猶予期間を超えてもreaderがクリティカルセクションから抜けない)の検出コード関連のオプションですが、あまり重要でないので割愛。
CONFIG_RCU_USER_QS
実行がユーザモードに戻ったことをクリティカルセクションから抜けたと見なすか否かのオプションだったようです。Linux 4.3ではCONFIG_NO_HZ_FULLに置き換わっているようです。
CONFIG_RCU_FANOUT, CONFIG_RCU_FANOUT_LEAF, CONFIG_RCU_FANOUT_EXACT
Hierarchical RCUの階層構造の一つのノードに対する子ノードの数などを制御するオプションです。
CONFIG_RCU_FAST_NO_HZ
CPUがticklessな状態になっている時に、猶予期間のチェックを減らすか否かのオプション1。CPUを頻繁に起こさなくて済むので、電力消費量が減る一方で、writerが待たされる期間が延びる。
CONFIG_TREE_RCU_TRACE, CONFIG_RCU_TRACE
RCUのトレースを有効にするか否かのオプションです。
CONFIG_RCU_KTHREAD_PRIO
RCUのためのカーネルスレッドのSCHED_FIFOの優先度を指定するオプションです。このカーネルでは0のようですが、これは内部的に1として扱われます2。SCHED_FIFOなスレッドは普通のスレッド(SCHED_OTHER)より先にCPUが割り当てられるので問題ないのだと思われます。
Kconfigには、SCHED_FIFOでCPUを使い切るようなプロセスがある場合には、そのプロセスより高い優先度に設定しろと書いてあります。
CONFIG_RCU_NOCB_CPU, CONFIG_RCU_NOCB_CPU_NONE, CONFIG_RCU_NOCB_CPU_ZERO, CONFIG_RCU_NOCB_CPU_ALL
RCUのコールバックを実行しないCPUを設定するオプションです。実行によるユーザプロセスへの影響(OS jitter)を減らしたい場合に使うようです。
CONFIG_RCU_NOCB_CPU
を有効にしたカーネルはrcu_nocbs
というカーネルブートパラメタを受け付けるようになり、ここにコールバックを実行しないCPUを指定できるようになります。
その他のオプションは、テスト等でブートパラメタで指定しにくく、カーネルコンフィグオプションで設定したい場合に使うようです。
CONFIG_SPARSE_RCU_POINTER
LinuxのRCUのコードを読んでみる (rcu_read_{lock,unlock}編)でも少し取り上げましたが、Sparseという静的コード解析ツールのためのヒントを有効にするオプションです。
RCUのターゲットとなるオブジェクトを入れるポインタ変数に__rcu
という修飾子が付いているを見たことがあるかもしれませんが、これがSparseへのヒントになります。rcu_dereference
といったAPIに渡すポインタ変数にこの__rcu
修飾子が付いていなければ警告を出してくれます。
CONFIG_RCU_TORTURE_TEST
RCUのテストを有効にするか否かのオプションです。もしモジュールになっていれば、そのカーネルモジュールをロード/アンロードすることでテストが実行できます。Documentation/RCU/torture.txt
にありますが、
#!/bin/sh
modprobe rcutorture
sleep 3600
rmmod rcutorture
dmesg | grep torture:
のようにテストが実行できます。
CONFIG_RCU_CPU_STALL_TIMEOUT, CONFIG_RCU_CPU_STALL_INFO
TIMEOUT
の方は、前述のストールしたか否かを判断する時間を指定するオプションです。INFO
の方は、ストールした時に追加情報を表示させるか否かのオプションです。
おわりに
RCUは機能がたくさんあって、いきなりコードを読むとしんどかったので、全容を掴むためにカーネルコンフィグを読んでみました。Linuxは機能がたくさんあって、カーネルコンフィグを読むだけでも楽しめますよね。
次回からはまたコード解析をしていきたいと思います。