一覧OS-15-1 · OS状態の読み取り

CPU使用率とロードアベレージ

累積値の差分と分母をそろえ、CPU実行と待ちの情報を照合します。

説明

CPU使用率は一定区間にCPUが何に時間を使ったかを表します。load averageは実行可能な仕事や特定の待ちを含む負荷の平均で、CPU使用率とは別の指標です。

4CPUの20秒間の記録を集計し、全体と個別CPUの割合、iowaitとsteal、タスク状態を調べます。最後に一つのプロセスのCPU時間を、1CPU基準とホスト全体基準で表示します。

1CPU時間の累積値

cpu-before.txtとcpu-after.txtは、4論理CPUを持つLinuxの/proc/stat形式の教材記録です。20秒間隔、USER_HZ=100、guestとguest_niceは0に固定しています。

cat cpu-before.txt区間の開始値; cat cpu-after.txt20秒後の値

各行はuser、nice、system、idle、iowait、irq、softirq、steal、guest、guest_niceの順です。値は起動後の累積時間なので、現在の負荷を求めるには同じ項目の差分を取ります。guestはuser等に含まれるため、二重に加算しません。

2区間の差分を作る

最初の8項目だけを使い、CPU行ごとの差分を表へ保存します。

awk 'NR==FNR {for(i=2;i<=9;i++) a[$1,i]=$i; next} {printf "%s",$1; for(i=2;i<=9;i++) printf " %d",$i-a[$1,i]; print ""}'同じCPU・項目の差分 cpu-before.txt cpu-after.txt > cpu-delta.txt差分を保存; cat cpu-delta.txt区間のCPU時間

全体の差分は8000tick、CPUごとは2000tickです。4CPU×20秒×100tick/秒と対応します。全体の割合と単一CPUの割合では分母が異なります。

3idleとiowaitを除いた割合

ここでは全体からidleとiowaitを引いた割合を表示します。使用率という名前だけでなく、計算方法を明示して読みます。

awk '{total=0; for(i=2;i<=9;i++) total+=$i; printf "%s non-idle/non-iowait=%.1f%%\n",$1,100*(total-$5-$6)/total}'式を固定して割合を算出 cpu-delta.txt同じ区間の差分

全体は20%、cpu0は80%、残る三つは0%です。全体だけを見ると局所的な偏りが隠れます。また、この式にはstealが含まれ、ゲスト自身の命令実行だけを表す割合ではありません。

4I/O待ちとstealを別に表示

cpu0のiowaitとstealを個別に確認します。

awk '$1=="cpu0" {printf "iowait=%.1f%% steal=%.1f%%\n",100*$6/2000,100*$9/2000}'待ちとstealの内訳 cpu-delta.txtcpu0の2000tick

iowait20%、steal5%です。LinuxのiowaitはI/O待ちタスクに関連する集計であり、特定ディスクの待ち時間をそのまま表す値ではありません。stealは仮想化環境で他の実行に使われた時間を表すため、ホスト側の競合も確認対象になります。

5load averageはCPU使用率ではない

同じ時点のload averageと、注目するタスク群の状態を読みます。

cat loadavg.txt負荷平均; cat cpu-tasks.csv同じ時点のタスク例

6.50、5.20、3.10は1・5・15分の負荷平均です。Linuxでは実行可能な状態Rだけでなく、割込み不能な待ちDも負荷に含まれます。2/120は現在の実行可能なスケジューリング対象と総数で、6.50の百分率表記ではありません。

6実行可能と待ち状態を分けて数える

教材表のRとDを数えます。この表は注目する8タスクだけで、システム全体の120個を列挙したものではありません。

awk -F, 'NR>1 {n[$2]++} END {printf "R=%d D=%d S=%d\n",n["R"],n["D"],n["S"]}'状態ごとの個数 cpu-tasks.csv注目するタスク群

Rが2、Dが5、Sが1です。この一時点の7個と、時間平均6.50は同じ値になる必要がありません。CPU実行だけでなく待ち状態が多い可能性を調べ、Dの原因は追加のI/O記録等で確認します。

7プロセスの使用率の分母

PID700のuserとsystemの累積値から、20秒間に使ったCPU時間を求めます。

awk -F, 'NR==2 {t=$1; u=$3; s=$4} NR==3 {seconds=($3-u+$4-s)/100; printf "cpu_seconds=%.1f one_cpu=%.1f%% four_cpus=%.1f%%\n",seconds,100*seconds/($1-t),100*seconds/(4*($1-t))}'累積差分から二種類の使用率 cpu-process.csvプロセスの20秒間の記録

CPU時間は12秒で、1CPU基準なら60%、4CPU全体基準なら15%です。ツールによって100%の基準が異なるため、同じ数値かどうかより、区間と分母をそろえて比較します。

まとめ

累積値は同じ時刻区間の差分にし、分母をそろえて比較します。

全体の低い使用率でも、一つのCPUに偏っている場合があります。

load average、iowait、プロセスの使用率は異なる情報を表します。

操作履歴と解説を振り返れます。

Bash / Linuxの記録

1
cat cpu-before.txt; cat cpu-after.txt
cpu 10000 0 4000 60000 1000 0 200 300 0 0
cpu0 4000 0 1000 12000 400 0 50 100 0 0
cpu1 2000 0 1000 16000 200 0 50 100 0 0
cpu2 2000 0 1000 16000 200 0 50 50 0 0
cpu3 2000 0 1000 16000 200 0 50 50 0 0
cpu 11000 0 4400 66000 1400 0 300 400 0 0
cpu0 5000 0 1400 12000 800 0 150 200 0 0
cpu1 2000 0 1000 18000 200 0 50 100 0 0
cpu2 2000 0 1000 18000 200 0 50 50 0 0
cpu3 2000 0 1000 18000 200 0 50 50 0 0
2
awk 'NR==FNR {for(i=2;i<=9;i++) a[$1,i]=$i; next} {printf "%s",$1; for(i=2;i<=9;i++) printf " %d",$i-a[$1,i]; print ""}' cpu-before.txt cpu-after.txt > cpu-delta.txt; cat cpu-delta.txt
cpu 1000 0 400 6000 400 0 100 100
cpu0 1000 0 400 0 400 0 100 100
cpu1 0 0 0 2000 0 0 0 0
cpu2 0 0 0 2000 0 0 0 0
cpu3 0 0 0 2000 0 0 0 0
3
awk '{total=0; for(i=2;i<=9;i++) total+=$i; printf "%s non-idle/non-iowait=%.1f%%\n",$1,100*(total-$5-$6)/total}' cpu-delta.txt
cpu non-idle/non-iowait=20.0%
cpu0 non-idle/non-iowait=80.0%
cpu1 non-idle/non-iowait=0.0%
cpu2 non-idle/non-iowait=0.0%
cpu3 non-idle/non-iowait=0.0%
4
awk '$1=="cpu0" {printf "iowait=%.1f%% steal=%.1f%%\n",100*$6/2000,100*$9/2000}' cpu-delta.txt
iowait=20.0% steal=5.0%
5
cat loadavg.txt; cat cpu-tasks.csv
6.50 5.20 3.10 2/120 7300
PID,STATE,NAME
700,R,worker
701,R,parser
702,D,reader
703,D,reader
704,D,reader
705,D,reader
706,D,reader
707,S,timer
6
awk -F, 'NR>1 {n[$2]++} END {printf "R=%d D=%d S=%d\n",n["R"],n["D"],n["S"]}' cpu-tasks.csv
R=2 D=5 S=1
7
awk -F, 'NR==2 {t=$1; u=$3; s=$4} NR==3 {seconds=($3-u+$4-s)/100; printf "cpu_seconds=%.1f one_cpu=%.1f%% four_cpus=%.1f%%\n",seconds,100*seconds/($1-t),100*seconds/(4*($1-t))}' cpu-process.csv
cpu_seconds=12.0 one_cpu=60.0% four_cpus=15.0%

演習完了