Mac OS Xのカーネル Xnuのメモ書き

スレッドのCPU利用率の計算


CPU使用量

スレッドを示すthread構造体にそのスレッドが、どれだけCPUを使用したかを示すcpu_usageというものがある(スレッド参照)。

この値はCPU利用率(%)ではなくCPU使用時間をベースにした値で、スケジューラの周期処理からupdate_priority()が呼ばれて定期的に更新される。

具体的にはCPU使用時間(System+User時間)を足し、前回の更新からの経過tick数
(*1)に応じ エージング(1tickにつき5/8を乗じる)して算出される。式は以下のとおり。

cpu_usage = (cpu_usage + delta)*(5/8)**(前回の更新からの経過tick数)

delta:前回の更新以降使用したCPU時間

単純に「cpu_usage = delta」としないのは、1tick内にスレッドが必ずスケジュールされるわけではないため、5/8エージングで過去のCPU使用量も反映させつつ現在の使用量を求めることで値を平滑化するため。


(*1) ここでtickはスケジューラの周期処理sched_tick_thread()が動作した回数

CPU利用率の算出

psコマンドで表示するCPU利用率(%)に変換するためにはcpu_usageを元に以下の計算を行なう。(小数点を含めて0.0〜100.0%なので0〜1000の値になる。TH_USAGE_SCALEは1000。)

    basic_info->cpu_usage = ((uint64_t)thread->cpu_usage
                              * TH_USAGE_SCALE) / sched_tick_interval;  (*2)
    basic_info->cpu_usage = (basic_info->cpu_usage * 3) / 5;            (*3)



(*2) CPU使用量をスケジューラ周期処理のタイマ値(sched_tick_interval)で割ることで単位時間あたりのCPU使用量を求める。また、%を0〜1000の値にするため、TH_USAGE_SCALEを乗じている。

(*3) (*2)で求めた単位時間あたりのCPU使用量を「CPUを100%使用した場合の単位時間あたりのCPU使用量」で割ることで%を算出する。式中でbasic_info->cpu_usage に 3/5を掛けているが3/5の意味は以下の通り。

「CPUを100%使用した場合の単位時間あたりのCPU使用量」はcpu_usageと同じく5/8 エージングをさせて

(5/8) + (5/8)**2 + (5/8)**3 + ...

で表すことができる。cpu_usageの算出と同じようにコードで書くと以下。
while (1) {
$full_usage += 1;
$full_usage = $full_usage * 5/8; #Ageing
}

これは 初項 a: 5/8、公比 r: 5/8の無限等比級数でその和はa/(1-r)となる。つまり(5/8)/(1-5/8)⇒(5/3)となる。この値でcpu_usageを割るので。 basic_info->cpu_usage * (3/5)となる。


実際の計算

実際にあるスレッドがCPUを50%使用し続けた場合、各値がどのように変化していくかを計算してみた。以下のPerlスクリプトで計算。

#!/usr/bin/perl

# $sched_tick_intervalの間に$cpu_usage_deltaだけCPUを使い続けるプロセスの
# CPU利用率の遷移を表示する

$cpu_usage_delta = 50; # intervalの間に使うCPU時間
$sched_tick_interval = 100; # スケジューラの起動周期
# 1Tickの時間はスケジューラの起動周期
# (sched_tick_interval)

$cpu_usage = 0;
$sched_ticks = 0;

# 1Loopはスケジューラsched_tick_thread()の起動に相当する
while(1) {
$sched_ticks++;

# CPU使用時間を加算
$cpu_usage += $cpu_usage_delta;

# 前回の更新から経過時間に応じてAgieng
# ここでは毎tick計算するものとして1tick分 ageing
$cpu_usage = $cpu_usage * 5 / 8;

# 単位時間あたりのCPU使用量
$pcpu = $cpu_usage * 100 / $sched_tick_interval;

# %を算出
$pcpu = $pcpu * 3 / 5;


printf("%4d %d %3.1f\%\n", $sched_ticks, $cpu_usage, $pcpu);
}


実行結果は以下の通り。(1カラム目:sched_ticks, 2カラム目:cpu_usage, 3カラム目:CPU利用率)
   1  31  18.8%
2 50 30.5%
3 62 37.8%
4 70 42.4%
5 75 45.2%
6 78 47.0%
7 80 48.1%
8 81 48.8%
9 82 49.3%
10 82 49.5%
11 82 49.7%
12 83 49.8%
13 83 49.9%
14 83 49.9%
15 83 50.0%
16 83 50.0%
17 83 50.0%
18 83 50.0%
:
5/8 Ageingによりすぐには50%にはならないが、CPUを使用し続けていくと徐々に上昇して50%になった。


最終更新 2006/05/31 17:03:09 - kztomita
(2006/05/31 15:14:18 作成)


最近更新したページ