2017-12-03

"Linux カーネル Hacks" 高橋浩和 監修

"GNU is not Unix !" という自由を象徴するような言葉遊びがあるが、"Linux is GNU ?" と問えば論争になる。人間の縄張り意識は果てしなく続く。自由をめぐってのものとなると尚更...
自己にとって自由精神ほど手強い相手はないかもしれない。自由になるためには知識がいる。それなりに金もいる。そして、なにより時間と空間がいる。空間は仮想的になんとか誤魔化せるし、コンピューティングの最も得意とするところ。そもそも精神空間がバーチャルな存在ときた。
だが、時間はそうはいかない。哲学が暇人の学問と言われる所以がここにある。凡人に出来ることと言えば、無駄な時間をできるだけ削ることぐらい。ただ、何が無駄で何が大切なのかが分からない。行き詰まると... 自分でやれない事は素直に諦めな!... とメフィストフェレスが耳元で囁く。誰かがヒントを与えてくれたとしても、手取り足取り教えてくれる者はいない。そこには、常に自己責任がつきまとう。だから自由なのだ。
なぜ、ハッキングの衝動に駆られるのか?自由を欲するが故に。環境をハッキングしては自分色に染め、アプリケーションをハッキングしては自分の手足とし、核をハッキングしてはすべてを手懐けようとする。なぜ、コンピュータを相手に?人の心をハッキングすることは難しすぎる。自己のハッキングを試みても、頭はいつも Kernel Panic !!
そして、監修者が冒頭から仕掛けてくる言葉が、いつまでも耳に残る...
「いまだ、ソースのないプロブラムは信用できないでいる...」

厳密に言えば、Linux は Unix とは認められていない。これだけ Unix ライクでありながら。これだけ PC-Unix という地位を確立していながら。その線引については様々な見解を呼びそうだが、やはりカーネルの仕組みにありそうか...
Linux の前身 Minix はマイクロカーネルであり、こちらの方が  Unix っぽい。ファイルシステムやメモリ管理などを独立したプロセスとしてカーネルの外に置くという方式は、小さな部品を集めて多様な処理をするという Unix 哲学に適っており、柔軟性も移植性も高い。ただ、実用性に耐えない!
一方、Linux はあえてモノリシックカーネルの道を選んだ。非力な x86 アーキテクチャのために、チューニング思想を優先したのである。それは、プロセス管理、メモリ管理、ファイルシステムなどのコードを一体化させ、一つのアドレス空間で実行するというやり方で、vmlinux に収められる。それでも、カーネルモジュールという動的に機能を追加や削除できる仕組みによって柔軟性が高められ、今では、x64, Alpha, arc, arm への移植性も担保される。しかも、このチューニング思想はリアルタイム性を重視する組込系システムとも相性がよく、いまや、Unix クローンとしての存在感は大きい。
こうした流れも、オープンソースによって後押しされてきた。オープンソースの世界とは、ソースコードが公開されるという事よりも、有能な人材を自由に解放するという事の方がずっと本質なのだろう。本書に名を連ねる方々も、これが趣味から昂じた世界であることを教えてくれる。
Unix を権威主義的とするなら、Linux は民主主義的である。ただ、あまりにも民主主義的すぎる。実に多くのディストリビューション、実に多くのバージョンが混在し、いまや単一のリポジトリでは管理しきれない。そこで、分散型のリポジトリ管理が求められるわけだが、本書は Git の有難味を改めて味あわせてくれる...

本書には、リソース管理やパフォーマンス改善、ファイルシステムやネットワークのハッキング、あるいは省電力化のためのテクニックなどが紹介され、それぞれに興味深い。
しかしながら、個人的に注目したいのは、デバッグ、プロファイリング、トレースといった検証の立場からの視点である。どんな問題にしても解決策の第一歩は、まず観ること、自分がどんな状態にあるかを知ること、そして、それを知るためのエラー検出機構の在り方を問うこと。システム検証で最も厄介なのは、自己矛盾に陥ることだ。
カーネルをいじれば、当然ながら、それが正常に機能しているかを検証する必要がある。エラー検出機構の在り方を問えば、エラー状態を定義し、それをシミュレーションすることになる。例外処理を定義することは意外と難しく、デバッグ機能をデバッグするとは、まさに循環論的な問い掛けなのだ。
政治家は「第三者会議」という言葉がお好きなようだが、それは客観的に正当性を担保できるからである。では、第三者とはどういう立場の人間か?メンバーは誰が選出するのか?そこに政治的な思惑が絡めば、既に自己矛盾を孕んでおり、第三者会議のメンバーを選出するための第三者... その第三者を選出するための第三者... というように無限循環論に陥る。ちなみに、似たような用語に「有識者会議」ってやつもあるが、それで正当性が担保されるかは知らん。つまり、完全な検証とは、無限の試みとも言えるのである。
本書には、クラッシュテストやフリーズ検出、さらには、意図的に Kernel Panic を発生させる方法についても言及される。最悪な状態に陥ってもなお、自動的に再起動できるような仕掛けを作ることも可能なのだ。とはいえ、Kernel Panic にも様々な異常状態があり、再起不能な状態も十分に考えられる。脆弱性をつかれたり、ハードウェアが破壊されたり。今日では一般的となったプログラマブルデバイスにしても、ハードウェアでありながら外部からプログラミングできる代物だ。人間社会は妥協で成り立ち、人間意識は妥協の中をもがき続ける。そして、システムも確率的な存在であり続ける...

1. Git 型民主主義
バージョン管理システムといえば、CVS を思い浮かべる。ちなみに、おいらは RCS に馴染んできたネアンデルタール人だ。
CVS では、リポジトリからローカル作業領域にソースコードを借り受け、修正したコードをリポジトリにコミットするといった手順を踏む。こうした単一型リポジトリは、複数の開発者が一つのリポジトリにコミットする。
一方、Git は分散型リポジトリを採用し、作業領域そのものがリポジトリとなる。ローカル領域がリポジトリとして完結しているという意味では、極めて民主主義的である。
Linux カーネルは、様々な形でソースツリーが存在する分散型の開発スタイルを持つ。最も代表的なソースツリーは、創始者に由来する Linus ツリー。他にも、将来のリリースに向けた linux-next ツリー。安定化バージョンの stable ツリー。モジュール毎に開発が進められる個別の開発ツリーといった形態があるようだ。そして、Linus ツリーが中央リポジトリとして認識されているが、それは暗黙的なもので、Git の仕組みにそのような階層的な定義はないらしい。
そういえば、社会人類学者レヴィ=ストロースは、首長の存在意義について、共同体の必要性から生まれるものではない... というようなことを語っていた。集団社会を形成する上で、それを仕切る者、すなわち政治的な存在が必要だとする考えは、世間では常識とされる。だが、人間が支配欲に憑かるのは本能的な欲望からであり、これに義務という意識が絡んで複雑化させる。誰もが参加できる開発組織では、権威的な存在は自然発生する以外には無用であろう。
ただ、メーリングリストには... コーディング規約に従っていないので直すように... といった指摘を見かける。指摘される側も、自発的なだけに恥ずかしい思いをする。誰もが参加できる!というのは、実はハードルが高い。実は、権威主義的な監視よりも民主主義的なプレッシャーの方が、はるかに厳しいのかもしれない。なるほど、分散型リポジトリとは、自己責任型であったか...

2. リソース管理
カーネルの主な仕事にリソース管理がある。CPU 時間を割当てるプロセススケジューラ、物理メモリや仮想メモリの割当て、ディスク I/Oの制御などである。
本書では、Linux カーネル特有なリソース管理法として、Cgroup(Control group)と Namespace(名前空間)、そして、この二つの機能を利用した LXC(Linux Container) の使用例を紹介してくれる。Cgroup 自体は、プロセスをグループ化するための機能とインターフェースを提供するもので、これを利用してリソース管理機能が実装されるという。Cgroup が提供するサブシステムは、こんな感じ...

$ cat /proc/cgroups

#subsys_name  hierarchy  num_cgroups  enabled
cpuset                2            1        1
cpu                   8            1        1
cpuacct               8            1        1
memory                9            1        1
devices               6           52        1
freezer              10            1        1
net_cls               8            1        1
blkio                 7            1        1
perf_event           11            1        1
hugetlb               4            1        1
pids                  5            1        1
net_prio              8            1        1

そして、Namespace を使うことでプロセスグループ毎に独立した PID や IPC、あるいは、ネットワーク空間やマウント空間を持たせることができるという。名前空間を分割するには、clone システムコールへの引数にフラグを設定して行う。

3. スケジューリングポリシー
スケジューリングポリシーのクラスは、大きく二つに分けられるという。TSS クラスとリアルタイムクラスである。マルチタスク環境では、一般的にプロセスは時分割で動作するが、実時間の保証が要求される処理では、静的に優先度を指定したい。これが、リアルタイムクラスである。例えば、こんなスケジューリングポリシーが定義されている...

SCHED_OTHER         : 標準 TSS クラス
SCHED_FIFO          : 静的優先度を持つ RT クラス
SCHED_RR            : ラウンドロビンでFIFOと違ってタイムスライスを持つ RT クラス
SCHED_BATCH         : 対話型でないとみなされ、休止時間による優先度の変更なし
SCHED_IDLE          : 他のプロセスがなくなって、やっと実行権が与えられる
SCHED_RESET_ON_FORK : リアルタイムクラスの実行を制限する特殊フラグ

スケジューリングポリシーに対するシステムコールも用意され、chrt コマンドは、ユーザレベルでスケジューリングポリシーを変更できる。おっと、i オプションに誘惑されそう。そういえば、おいらが好青年と呼ばれていた新入社員の時代、先輩からメインフレーム上でジョブの優先度を下げられるという悪戯をされたものだ。

# chrt --help
Show or change the real-time scheduling attributes of a process.

Set policy:
 chrt [options]   [...]
 chrt [options] --pid  

Get policy:
 chrt [options] -p 

Policy options:
 -b, --batch          set policy to SCHED_BATCH
 -d, --deadline       set policy to SCHED_DEADLINE
 -f, --fifo           set policy to SCHED_FIFO
 -i, --idle           set policy to SCHED_IDLE
 -o, --other          set policy to SCHED_OTHER
 -r, --rr             set policy to SCHED_RR (default)

Scheduling options:
 -R, --reset-on-fork       set SCHED_RESET_ON_FORK for FIFO or RR
 -T, --sched-runtime   runtime parameter for DEADLINE
 -P, --sched-period    period parameter for DEADLINE
 -D, --sched-deadline  deadline parameter for DEADLINE
  ...

また、リアルタイムクラスの CPU 時間を制限するための機能として、RT Group Scheduling と RT Throttling が紹介される。sysctl を使って取得と設定を行うには、こんな感じ...

# sysctl -n kernel.sched_rt_runtime_us
950000

# sysctl -w kernel.sched_rt_runtime_us=-1
尚、設定値 = -1 は、ランタイムクラスに対する CPU 時間の制限をなくす。

4. 省電力
電源管理のインターフェース規格に、ACPI(Advanced Configuration and Power Interface)ってやつがあり、動作モード、休止モード、シャットダウン状態でも若干の電力消費があるモード、あるいは、完全なシャットダウンモードといった電力状態が定義される。
ただ、この手の機能は昔からトラブルの元で、ハイバネーションにしても、ネアンデルタール人はことごとく機能をぶった切る性癖がある。とはいえ、最近はそうも言ってられない。実際、WON(Wake On LAN)といった機能は、外出先からジョブを覗くのに重宝している。例えば、いくつかのシミュレーションをバッチで実行させ、外出先からログを監視することで仕事をやっているふりができる。もちろん夜の社交場からでもアクセス可能だ。
本書は、OpenIPMI について触れてくれる。IPMI(Intelligent Platform Management Interface)も、リモートで電源管理できる仕組み。WON の場合、MAC アドレスを指定するために、マジックパケットが届かない場合があるが、IPMI の場合は、IP アドレスを指定するために汎用性が高いという。WON は、NIC が対応していれば利用できるが、VLAN や VPN などを経由すると、MAC アドレスが見えなくなったりする。
対して、IPMI は、ベースボード管理コントローラ(BMC)が搭載されている必要があり、サーバマシンなどに限定されるという。
また、アプリケーションの電力消費の指標を表示してくれる powertop コマンドを紹介してくれる。

# yum install powertop

# powertop
Summary: 5875.4 wakeups/second,  0.0 GPU ops/seconds, 0.0 VFS ops/sec and 32.4% CPU use

      Usage       Events/s    Category       Description
   21.3 ms/s     4417.5       Timer          hrtimer_wakeup
    2.7 ms/s     344.8        Timer          tick_sched_timer
    1.0 ms/s     143.7        Process        [rcu_sched]
  571.1 μs/s     142.7       kWork          cs_dbs_timer
    3.4 ms/s     134.1        Interrupt      [30] nvkm
   22.6 ms/s     107.3        Process        /usr/bin/gnome-shell
   43.7 ms/s     103.4        Process        gnome-system-monitor --show-resources-tab
    4.2 ms/s      60.3        Interrupt      [27] hpet5
    8.3 ms/s      55.6        Interrupt      [24] hpet2
   12.1 ms/s      52.7        Interrupt      [25] hpet3
  125.1 ms/s       1.0        Process        /usr/bin/X :0 -background none -noreset -audit 4 -verbose -auth /
    1.6 ms/s      24.9        kWork          nouveau_fence_work_handler
    1.4 ms/s      24.9        Process        /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plu
    2.4 ms/s      23.9        Interrupt      [26] hpet4
  131.7 μs/s     23.0        Process        [usb-storage]
    7.3 ms/s      19.2        kWork          nv50_disp_atomic_commit_work
   20.4 ms/s      10.5        Process        [kworker/u16:1]
  160.7 μs/s     19.2        Process        [xfsaild/dm-1]
  158.5 μs/s     19.2        Process        [xfsaild/dm-2]
    2.1 ms/s       8.6        Process        [kworker/u16:3]
   27.0 ms/s      0.00        Process        powertop
     ...

5. SysRq キー : Magic System Request Key
本書は、クラッシュダンプの採取、クラッシュテスト、ウォッチドッグタイマによるフリーズの検出など様々なテクニックを紹介してくれる。
特に注目したいのは、キーボードの特定キーを使って、一発でカーネル内の情報を取得できる方法である。通常は proc ファイルシステムを覗くかコマンドで情報を取得するが、システムがフリーズするとコマンドも受け付けられない。そこで、SysRq キーというわけである。
この機能を使うためには、CONFIG_MAGIC_SYSRQ を有効にしてカーネルをコンパイルするという。
尚、RedHat 系では最初からカーネルに組み込まれていて、sysctl コマンドにより有効/無効を設定できる。ちなみに、CentOS 7 で試すと、こんな感じ...

# sysctl -w kernel.sysrq=1

あるいは、

# echo 1 > /proc/sys/kernel/sysrq

このマジックキーは、/proc/sysrq-trigger にコマンド発行することによって実行されるようだ。

# echo [key] > /proc/sysrq-trigger
尚、key は、b で reBoot, c で Crashdump...

6. perf tools
本書は、perf tools によるパフォーマンス解析、ftrace を使った動作解析、SystemTop を使ったプログラマブルトレーシングを紹介してくれる。これらの機能はカーネルの解析だけでなく、ユーザプログラムの解析やトラブルシューティングにも有用である。
perf tools とは、Linux カーネル上の統合パフォーマンスプロファイリングツールで、CPU 内蔵のパフォーマンスカウンタや、カーネルのトレースポイントを使ってプロファイリングが行えるという。
同様のツールに、Oprofile ってやつがあるが、カーネルとのメンテナンス頻度が違うために、サポートが追いついていないようである。perf tools はカーネルのソースコードにマージされているので、その点では安心できそう。実行イメージは、こんな感じ...

# yum install perf

# perf top
Samples: 991  of event 'cycles', Event count (approx.): 602222914
Overhead  Shared Object         Symbol
  9.94%  [kernel]              [k] module_get_kallsym
  5.64%  [kernel]              [k] ioread32
  4.27%  [kernel]              [k] format_decode
  2.73%  [kernel]              [k] vsnprintf
  2.48%  [kernel]              [k] number.isra.2
  2.43%  [kernel]              [k] kallsyms_expand_symbol.constprop.1
  2.43%  [kernel]              [k] string.isra.7
  2.39%  perf                  [.] rb_next
  2.35%  [kernel]              [k] __memcpy
  2.19%  libc-2.17.so          [.] __strcmp_sse42
  2.15%  perf                  [.] __dso__load_kallsyms
  2.06%  [kernel]              [k] strnlen
  1.96%  perf                  [.] rb_insert_color
  1.91%  libpixman-1.so.0.34.0 [.] pixman_edge_init
   ...

# perf stat -e cycles,instructions,cache-references,cache-misses,bus-cycles -a sleep 10

Performance counter stats for 'system wide':

  10,766,726,847      cycles
   8,240,154,632      instructions      # 0.77  insn per cycle
      92,804,452      cache-references
       8,681,674      cache-misses      # 9.355 % of all cache refs
       bus-cycles

    10.002226767 seconds time elapsed

7. PEBS と LBR
PEBS(Precise Event Based Sampling)とは、Intel Core マイクロアーキテクチャから導入されたパフォーマンスカウンタ。NetBurst マイクロアーキテクチャの一部でも採用されているようだ。適用できるイベントは限られるが、正確なアドレスを割り出せる。
従来のパフォーマンスカウンタは、イベント発生後に外部割込みを発生させるため、発生時点から少し遅れてしまい、正確なアドレスを検出できない。x86 アーキテクチャは、CISC命令を採用しているので命令長もばらばら。その点、PEBS はイベント発生直後のアドレスが取得できるという。
それでも、分岐命令に出くわそうものなら、追っかけるだけで大変だが、perf tools では、PEBS に LBR(Last Branch Record) を組み合わせて、分岐命令から逆算までやってくれるという。ただし、この機能を利用するにもプロセッサ次第で、未対応なら ENOTSUP エラーが返されることに...

0 コメント:

コメントを投稿