TenForward

技術ブログ。はてなダイアリーから移転しました

Linux 3.16 から試せる cgroup の単一階層構造 (2)

前回の続きです。

グループで使えるサブシステム

"cgroup.subtree_control" ファイルにサブシステムを指定することで子グループで使えるサブシステムが指定できることを前回説明しました。

これに対して、あるグループで使えるコントローラを一覧できる "cgroup.controllers" ファイルがディレクトリごとに存在します。

まず "root" グループの "cgroup.controllers" にはシステム全体で使えるコントローラが書かれています。

# cat /sys/fs/cgroup/cgroup.controllers 
cpuset cpu cpuacct memory devices freezer net_cls blkio perf_event net_prio hugetlb

"parent" とその下に "child" グループ用のディレクトリを作成します。

# mkdir /sys/fs/cgroup/parent
# mkdir /sys/fs/cgroup/parent/child

"parent" 以下でサブシステムが使えるように root グループの "cgroup.subtree_control" にサブシステムを書き込みます。

# echo "+memory +cpu" > /sys/fs/cgroup/cgroup.subtree_control    

これを確認するために、"parent" グループの "cgroup.controllers" ファイルを確認します。

# cat /sys/fs/cgroup/parent/cgroup.controllers 
cpu memory

"parent" グループで cpu と memory が有効になりましたね。

同様に "parent" グループの "cgroup.subtree_control" にサブシステムを書き込むと、その子である "child" の "cgroup.controllers" に表示されます。

# echo "+cpu +memory" > /sys/fs/cgroup/parent/cgroup.subtree_control
# cat /sys/fs/cgroup/parent/child/cgroup.controllers cpu memory

つまり親グループの "cgroup.subtree_control" にサブシステムを書き込むと、その子グループの "cgroup.controllers" にその結果が反映されるわけですね。

プロセスの登録ファイル

グループの作成方法とサブシステムの登録方法を見た所で、次はプロセスのグループへの登録です。以前はグループにある "tasks" というファイルに PID を登録しました。これが新しいcgroupでは "cgroup.procs" というファイルになっています。"tasks" ファイルはありません。

わざわざ名前変えなくても…、と思う所ですが、実は意味があります。「まともな」cgroup と今の cgroup では粒度が違います。"tasks" は文字通り「タスク単位」で登録されていました。"tasks" ファイルの中を見るとプロセスIDだけでなくスレッドIDも登録されていました。sane_behavior オプション付きだと、これが「プロセス単位」となります

例えば Apache を起動させて cgroup に登録し、ID の登録状況をみてみます。

# mount -t cgroup -o all cgroup /sys/fs/cgroup/
# ps -Lm 2677
  PID   LWP TTY      STAT   TIME COMMAND
 2677     - ?        -      0:00 /usr/sbin/httpd -k start
    -  2677 -        Sl     0:00 -
    -  2711 -        Sl     0:00 -
    -  2712 -        Sl     0:00 -
    -  2713 -        Sl     0:00 -
    : (snip)
# grep 2677 tasks 
2677
# grep 2711 tasks 
2711

2677 と 2711 は両方登録されていますね。

# mount -t cgroup -o __DEVEL__sane_behavior cgroup /sys/fs/cgroup
# ps -Lm 2703
  PID   LWP TTY      STAT   TIME COMMAND
 2703     - ?        -      0:00 /usr/sbin/httpd -k start
    -  2703 -        Sl     0:00 -
    -  2761 -        Sl     0:00 -
    -  2762 -        Sl     0:00 -
    -  2763 -        Sl     0:00 -
    : (snip)
# grep 2703 cgroup.procs 
2703
# grep 2761 cgroup.procs 
#

2703 は登録されていますが、2761 は登録されていません。

これに加えて、細かい変更ですが、cgroup.procs ファイル内の ID はソートされなくなっています (今の cgroup は番号順にソートされています)。

プロセスのグループへの登録

sane_behavior 付きでも登録方法は変わりありません。

# mkdir /sys/fs/cgroup/test
# echo $$ > /sys/fs/cgroup/test/cgroup.procs 
# cat /sys/fs/cgroup/test/cgroup.procs 
2961
2975

削除方法も同じです。親グループに登録します。

# echo $$ > /sys/fs/cgroup/cgroup.procs 
# cat /sys/fs/cgroup/test/cgroup.procs 

グループのプロセスの保持

ここが一番変わってるとこじゃないかなと思う所ですが、親子関係のグループがある場合、現在は親と子のそれぞれにタスクが登録できます。「まともな」オプションでは親子でプロセスを登録することは認められません。プロセスを持たないグループだけが子グループを持てます

"parent" にプロセスを登録してみます。

# echo $$ > /sys/fs/cgroup/parent/cgroup.procs      
# cat /sys/fs/cgroup/parent/cgroup.procs 
2961
3009

この状態で "child" を使うために "parent" の cgroup.subtree_control ファイルに cpu と memory を書いてみます。

# echo "+memory +cpu" > /sys/fs/cgroup/parent/cgroup.subtree_control 
-bash: echo: write error: Device or resource busy

できません。

"parent" からプロセスを一旦抜いてみます (root に登録)。

# echo $$ > /sys/fs/cgroup/cgroup.procs

その上で "parent" の "cgroup.subtree_control" にサブシステムを書き込んでみます。

# echo "+memory +cpu" > /sys/fs/cgroup/parent/cgroup.subtree_control 
#

エラーなく書き込めました。"child" の "cgroup.controllers" ファイルを見ると、

# cat /sys/fs/cgroup/parent/child/cgroup.controllers 
cpu memory

"parent" で登録したサブシステムが登録されています。

つまり root グループを除いて、"cgroup.subtree_control" と "cgroup.procs" の両方に登録があるという状態はないわけです。

このような仕様になった理由ですが、今の cgroup のように親子両方にタスクが登録できると、親グループのタスクと子グループのタスクでのリソース競合が起き、リソース配分が非常に難しくなるからのようです。親の内部タスクと子のプロセスの間でどうリソースを配分すべきかの決まったものはないようですし、サブシステムごとに異なった実装になっているようです。

「まともな」動きのように子を持つ場合は親はプロセスを持たないということにすれば、このような問題は起きませんね。

まとめ

今回出てきた sane_behavior オプションの特徴をまとめましょう。

  • グループで使用できるサブシステムは "cgroup.controllers" に書かれている
  • 親グループの "cgroup.subtree_control" にサブシステムを書き込むと、その子グループの "cgroup.controllers" にその結果が反映される
  • グループへの登録の単位はプロセスになった
  • プロセスを持たないグループだけが子グループを持てる

おまけ

今マウントしているのが sane_behavior かそうでないか?を確認したいという場合は root グループに "cgroup.sane_behavior" というファイルがあります。

sane_behavior な時はこのファイルに "1" が、そうでない場合は "0" が書かれています。

# cat /sys/fs/cgroup/cgroup.sane_behavior 
1