読者です 読者をやめる 読者になる 読者になる

NetBSDのスケジューラを読んでみるめも3

netbsd kernel

φ(.. )メモシテオコウ このシリーズ3回目はsched_setrunnable()sched_nice()を見てみます。

まずはsched_setrunnable()から。

    331 void
    332 sched_setrunnable(struct lwp *l)
    333 {
    334 
    335  	if (l->l_slptime > 1)
    336  		updatepri(l);
    337 }

内容としては「(´-`).。oO(lwpが1秒(単位は秒ですよね?)以上寝てたらプライオリティを変えるんだな」と予測できますね。

    125 	u_int		l_slptime;	/* l: time since last blocked */

sys/sys/lwp.hで変数のコメント見てみると↑ように書かれています。

それではsched_setrunnable()の処理の本体と言えるupdatepri()を見ましょう。

    310 static void
    311 updatepri(struct lwp *l)
    312 {
    313 	fixpt_t loadfac;
    314 
    315 	KASSERT(lwp_locked(l, NULL));
    316 	KASSERT(l->l_slptime > 1);
    317 

ここまでは特に問題無いですね。

    318 	loadfac = loadfactor(averunnable.ldavg[0]);

loadfactor()は関数では無くてsched_4bsd.cで定義しているマクロとなっています。

    236 /* calculations for digital decay to forget 90% of usage in 5*loadav sec */
    237 #define	loadfactor(loadav)	(2 * (loadav) / ncpu)

このマクロについている説明はFreeBSDカーネルの設計と実装のP140にある「減衰処理が5回行われると~」というところに該当してそうです。
averunnable.ldavgは昨日調べたので飛ばします。

    319 
    320 	l->l_slptime--; /* the first time was done in sched_pstats */

l_slptimeの値を1減らして(負にならない or なってもOKということ?)

    321 	l->l_estcpu = decay_cpu_batch(loadfac, l->l_estcpu, l->l_slptime);

cpuの利用度をdecay_cpu_batch()で再計算します。

    258 /*
    259  * For all load averages >= 1 and max l_estcpu of (255 << ESTCPU_SHIFT),
    260  * sleeping for at least seven times the loadfactor will decay l_estcpu to
    261  * less than (1 << ESTCPU_SHIFT).
    262  *
    263  * note that our ESTCPU_MAX is actually much smaller than (255 << ESTCPU_SHIFT).
    264  */
    265 static fixpt_t
    266 decay_cpu_batch(fixpt_t loadfac, fixpt_t estcpu, unsigned int n)
    267 {
    268 
    269 	if ((n << FSHIFT) >= 7 * loadfac) {
    270 		return 0;
    271 	}
    272 

if文が真になる場合はcpuが使われていないということで利用度0を返す。

    273 	while (estcpu != 0 && n > 1) {
    274 		estcpu = decay_cpu(loadfac, estcpu);
    275 		n--;
    276 	}
    277 
    278 	return estcpu;
    279 }
    280 

decay_cpu()昨日調べましたね。
decay_cpu()で計算したcpu利用度と引数で渡ってきたnの値を使ってwhile文の条件が偽になるまでcpu利用度を計算しつづけると。
そして、cpu利用度の計算が終わったらresetpriority()を呼び出してプライオリティの更新を実行です。

    322 	resetpriority(l);
    323 }

resetpriority()昨日調べたやつです。
と、ここまでがsched_setrunnable()で次はsched_nice()を見てみましょう。

    339 void
    340 sched_nice(struct proc *p, int n)
    341 {
    342 	struct lwp *l;
    343 
    344 	KASSERT(mutex_owned(p->p_lock));
    345 
    346 	p->p_nice = n;

まずはプロセスのnice値の変更。

    347 	LIST_FOREACH(l, &p->p_lwps, l_sibling) {
    348 		lwp_lock(l);
    349 		resetpriority(l);
    350 		lwp_unlock(l);
    351 	}
    352 }
    353 

次にプロセスに所属しているlwp全てに対してプライオリティを変更します。プロセスのnice値を変更するわけだからそのプロセスが持つ全lwpが対象になりますね。

こう見ていると昨日調べたdecay_cpu()、resetpriority()がsched_4bsd.cの重要な関数なんだなーって思いますね。
(´-`).。oO(この辺の挙動を理解することが大事ですねぇ