〆(.. )カリカリッ!! sched_schedclock()です。
関数本体よりもコメントの方が多いですね。
376 /* 377 * We adjust the priority of the current LWP. The priority of a LWP 378 * gets worse as it accumulates CPU time. The CPU usage estimator (l_estcpu) 379 * is increased here. The formula for computing priorities will compute a 380 * different value each time l_estcpu increases. This can cause a switch, 381 * but unless the priority crosses a PPQ boundary the actual queue will not 382 * change. The CPU usage estimator ramps up quite quickly when the process 383 * is running (linearly), and decays away exponentially, at a rate which is 384 * proportionally slower when the system is busy. The basic principle is 385 * that the system will 90% forget that the process used a lot of CPU time 386 * in 5 * loadav seconds. This causes the system to favor processes which 387 * haven't run much recently, and to round-robin among other processes. 388 */ 389 390 void 391 sched_schedclock(struct lwp *l) 392 { 393 394 if (l->l_class != SCHED_OTHER) 395 return; 396 397 KASSERT(!CURCPU_IDLE_P()); 398 l->l_estcpu = ESTCPULIM(l->l_estcpu + ESTCPU_ACCUM); 399 lwp_lock(l); 400 resetpriority(l); 401 lwp_unlock(l); 402 }
まずスケジューリングポリシーをチェックしてSCHED_OTHER以外のFIFOとかRound-robinなプロセスの場合は何もせずにreturnします。
次にcpu使用率の計算をESTCPULIMマクロを使って実行。このマクロはsched_4bsd.c内で定義されています。
167 #define ESTCPU_SHIFT 11 168 #define ESTCPU_MAX ((PRIO_MAX - 2) << ESTCPU_SHIFT) 169 #define ESTCPU_ACCUM (1 << (ESTCPU_SHIFT - 1)) 170 #define ESTCPULIM(e) min((e), ESTCPU_MAX)
ここでESTCPU_MAXのところで(PRIO_MAX - 2)という式がありますが、この-2の意味はどこかで読んだ気がするのですが思い出せません(´・ω・`)
PRIO_MAXはsys/sys/resource.hで定義されています。
40 /* 41 * Process priority specifications to get/setpriority. 42 */ 43 #define PRIO_MIN -20 44 #define PRIO_MAX 20
この様な感じでl_estcpuを設定したらresetpriority()を呼ぶという流れですね。
sched_schedclock()のコールフローはこのような流れです。
hardclock() --> schedclock() --> sched_schedclock()
hardclock()はkern_clock.cにあります。
タイマ割り込みを契機としてhardclock()が実行され、状況によってschedclock()を呼ぶようですね。
214 /* 215 * If no separate schedclock is provided, call it here 216 * at about 16 Hz. 217 */ 218 if (schedhz == 0) { 219 if ((int)(--ci->ci_schedstate.spc_schedticks) <= 0) { 220 schedclock(l); 221 ci->ci_schedstate.spc_schedticks = hardscheddiv; 222 } 223 }
schedhzが何者かというところですがsys/sys/sched.hでは16が理想と書かれています。
203 extern int schedhz; /* ideally: 16 */
nxrで検索したのですがi386とかamd64の場合は分かりませんでした(´・ω・`)ガッカリ…
しょうがないのでカーネルモジュール作ってprintfさせてみましたw 一応DragonFly BSDのカーネルモジュールはhello worldレベル程度は作ったことあるので似たようなもんだろうと思いつつ調べてたらカーネルソース内にサンプルを見つけたので運が良かったかも。
モジュールのコードはこれでschedhzをprintfするだけです。
#include <sys/cdefs.h> #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/sched.h> MODULE(MODULE_CLASS_MISC, test_mod, NULL); static int test_mod_modcmd(modcmd_t cmd, void *arg) { switch (cmd) { case MODULE_CMD_INIT: printf("shcedhz is %d\n", schedhz); break; case MODULE_CMD_FINI: printf("goodbye\\n"); break; case MODULE_CMD_STAT: break; default: printf("unknown param %d\n", cmd); return ENOTTY; } return 0; }
Makefileはこちら。
KMOD?= test-mod SRCS= test-mod.c .include <bsd.kmodule.mk>
あとは↓のようにモジュールをロードしてdmesgで確認すると…
[masami@nbsd:~/test-mod]$ sudo /sbin/modload ./test-mod.kmod
結果は0でした。
wsdisplay0: screen 1 added (80x25, vt100 emulation) wsdisplay0: screen 2 added (80x25, vt100 emulation) wsdisplay0: screen 3 added (80x25, vt100 emulation) wsdisplay0: screen 4 added (80x25, vt100 emulation) shcedhz is 0 [masami@nbsd:~/test-mod]$
それでは話をコールフローに戻して。。。
schedclock()もsys/kern/kern_clock.cにあり、このような関数です。
330 void 331 schedclock(struct lwp *l) 332 { 333 if ((l->l_flag & LW_IDLE) != 0) 334 return; 335 336 sched_schedclock(l); 337 } 338
アイドルプロセス以外ならsched_schedclock()を呼んでますね。