RCUのカーネルコンフィグオプションを調べる

*この記事は[Linux Advent Calendar 2015](http://qiita.com/advent-calendar/2015/linux)の12月7日分です。*

# はじめに

[LinuxのRCUを読んでみる (synchronize_rcu / call_rcu簡易版編)](http://qiita.com/peo3@github/items/a6c090f761b253ef4ff4)の続きというか番外編です。RCU関連のカーネルコンフィグオプションを調べていきます。今回はコードの解説はありません。

私がVMにセットアップしているFedora 21のカーネルなので、今回は4.0ベースです。4.3とそんなに変わらないと思います。

# Fedora 21のカーネルコンフィグオプションを調べる

以下はFedora 21のRCU関連のカーネルコンフィグオプションです。

```shell-session
$ 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](https://lwn.net/Articles/305782/)という実装を使うようになります。これはwriter側のデータ構造を階層構造にすることで、writerのロック競合を減らす目的で設計されました。

それ以外の実装といえば、[前回](http://qiita.com/peo3@github/items/a6c090f761b253ef4ff4)の記事で取り上げたユニプロセッサ版になります。

## CONFIG_SRCU

SRCUとは[Sleepable RCU](https://lwn.net/Articles/202847/)のことです。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な状態になっている時に、猶予期間のチェックを減らすか否かのオプション[^tickless]。CPUを頻繁に起こさなくて済むので、電力消費量が減る一方で、writerが待たされる期間が延びる。

[^tickless]: 別の言い方をするとRCUのコールバックがあっても、ticklessになることを許すオプション。

## CONFIG_TREE_RCU_TRACE, CONFIG_RCU_TRACE

RCUのトレースを有効にするか否かのオプションです。

## CONFIG_RCU_KTHREAD_PRIO

RCUのためのカーネルスレッドのSCHED_FIFOの優先度を指定するオプションです。このカーネルでは0のようですが、これは内部的に1として扱われます[^prio]。SCHED_FIFOなスレッドは普通のスレッド(SCHED_OTHER)より先にCPUが割り当てられるので問題ないのだと思われます。

[^prio]: SCHED_FIFOの優先度は1〜99なので。なぜ0になってるかは不明。

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}編)](http://qiita.com/peo3@github/items/5f2274f6c6740593d2af)でも少し取り上げましたが、[Sparse](https://en.wikipedia.org/wiki/Sparse)という静的コード解析ツールのためのヒントを有効にするオプションです。

RCUのターゲットとなるオブジェクトを入れるポインタ変数に`__rcu`という修飾子が付いているを見たことがあるかもしれませんが、これがSparseへのヒントになります。`rcu_dereference`といったAPIに渡すポインタ変数にこの`__rcu`修飾子が付いていなければ警告を出してくれます。

## CONFIG_RCU_TORTURE_TEST

RCUのテストを有効にするか否かのオプションです。もしモジュールになっていれば、そのカーネルモジュールをロード/アンロードすることでテストが実行できます。`Documentation/RCU/torture.txt`にありますが、

```shell-session
#!/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は機能がたくさんあって、カーネルコンフィグを読むだけでも楽しめますよね。

次回からはまたコード解析をしていきたいと思います。