cgroup の cpu.shares を検証した
cgroup には複数のサブシステム(controller)があるが、その中の cpu.shares
について検証してみた。
cpu.shares とは
cpu.shares を設定すると、タスクが使用できる CPU 時間の割合
を変更することができる。
具体的に言うと、A
B
2つのグループを作り、cpu.shares をそれぞれ1024
2048
とした場合、B のグループにいるプロセスが、A のグループにいるプロセスより 2倍 CPU を使えるようになる。以下、実行例。
1 | # mkdir /cgroup/{A,B} |
グループ B に登録した PID:2836 のプロセスが、グループ A に登録した PID:2835 の 2倍 CPU を使用している。
今回の疑問点
これだけなら、わかりやすいが、以下の点が不明だったので実際に検証してみた。
- グループ内に複数プロセスがいる場合どのように CPU が割り振られるのか
- ルートグループに属するプロセスの CPU の割り振りはどうなるか
環境
- マシン: Vagrant(CPU コア1)
OS:
- CentOS6.6 (2.6.32-504.16.2.el6.x86_64)
- CentOS7.1 (3.10.0-229.el7.x86_64)
今回検証したグループ構成
- CPU のルートグループ配下に
test
グループを作成する - test グループ配下に、
A
B
C
グループを作成する - 作成した全てのグループの
cpu.shares
は、全て1024
と同じにする
- CPU のルートグループ配下に
環境構築手順(CentOS6.6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18[root@localhost vagrant]# mkdir /cgroup
[root@localhost vagrant]# mount -t cgroup -o cpu cgroup /cgroup/
[root@localhost vagrant]# mkdir -p /cgroup/test/{A,B,C}
[root@localhost vagrant]# head /cgroup/{,test/{,{A,B,C}/}}cpu.shares
==> /cgroup/cpu.shares <==
1024
==> /cgroup/test/cpu.shares <==
1024
==> /cgroup/test/A/cpu.shares <==
1024
==> /cgroup/test/B/cpu.shares <==
1024
==> /cgroup/test/C/cpu.shares <==
1024CPU を使用するシェルスクリプト
loop.sh 1
2
3
4#!/bin/bash
CGROUP=$(mount|grep -w cpu|awk '{print $3}')
echo $$ > $CGROUP/tasks || exit 1
while : ; do : ; done1
2
3
4
5loop.sh & # ルートグループに自身の PID を登録し無限ループ
loop_test.sh & # test グループに自身の PID を登録し無限ループ
loop_test_A.sh & # test/A グループに自身の PID を登録し無限ループ
loop_test_B.sh & # test/B グループに自身の PID を登録し無限ループ
loop_test_C.sh & # test/C グループに自身の PID を登録し無限ループ自分自身の PID をスクリプト名にあったグループに登録し、無限ループを行うシェルスクリプト。
検証1
A
グループに、無限ループするプロセスを一つ登録した場合の CPU 利用状況。
1 | # 結果 |
ルート
->test
->A
と最下層のグループに登録されているが、CPU は 100% 利用できる。
検証2
A
B
C
の各グループに、無限ループをするプロセスを一つづつ登録した場合の CPU 使用状況。
1 | # 結果 |
- 各グループの cpu.shares の値は同じなので、均等に CPU を 1/3 (33.3%)づつ使用している。
検証3
検証2に加え、C
グループに、もう一つプロセスを登録した場合の CPU の利用状況。
1 | # 結果 |
- グループ A, B に割り当てられている CPU 時間は変わらない
- 検証2でグループ C に割り当てられていた CPU 時間(33.3%)は、2つのプロセス(2570,2573)に分配されている
検証4
検証3に加え、test
グループに無限ループするスクリプトを一つ、追加登録した場合の CPU 利用状況。
1 | # 結果 |
- CPU 時間は、test グループの1つのプロセス
1887
とグループA
B
C
で、4等分(25%)されている - C グループ 配下のプロセスは、4等分された CPU時間(25%) を分配して利用している
検証5
検証4に加え、さらにtest
グループに無限ループするスクリプトを一つ、追加登録した場合の CPU 利用状況。
1 | # 結果 |
- CPU 時間は、test グループの2つのプロセス
1892
1887
とグループA
B
C
で、5等分(20%)されている - test グループの2つのプロセス
1892
1887
は、それぞれ5等分された CPU時間(20%) を利用できる
検証6
検証3に加え、ルートグループに無限ループするスクリプトを一つ、追加登録した場合の CPU 利用状況。
1 | # 結果 |
- CPU 時間は、ルートグループの1つのプロセス
1898
とtest グループ
で、2等分(50%)されている - test グループ 配下のプロセスは、2等分された CPU時間(50%) を分配して利用している
検証7
検証6に加え、さらにルートグループに無限ループするスクリプトを一つ、追加登録した場合の CPU 利用状況。
1 | # 結果 |
- CPU 時間は、ルートグループの2つのプロセス
1898
1903
とtest グループ
で、3等分(33%)されている - ルートグループの2つのプロセス
1898
1903
は、それぞれ3等分された CPU時間(33%) を利用できる - test グループ 配下のプロセスは、3等分された CPU時間(33%) を分配して利用している
まとめ
検証7の結果を見れば、cpu.shares の振る舞いがだいたいわかる。
test グループ配下のプロセスが利用できる CPU時間は、ルートグループに属するプロセス数や CPU 利用状況によってかわるので、リソース設計が難しい。
このため、test グループの CPU時間を担保したい場合は、以下のような感じで、一旦ルートグループ配下の全プロセスを別のサブグループ配下に移動してあげればよさそう。
1 | mkdir /cgroup/root |