2012年01月10日 情報科学類 オペレーティングシステム II 筑波大学 システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2011/2012-01-10
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
表示 | 説明 |
NI | Nice。優先度を表す値。 |
$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1013 4795 4793 0 76 0 - 1719 wait pts/2 00:00:00 bash
0 S 1013 4905 4795 0 75 0 - 1503 - pts/2 00:00:00 xterm
0 T 1013 5031 4795 2 76 0 - 3577 finish pts/2 00:00:00 emacs-x
0 R 1013 5034 4795 0 78 0 - 557 - pts/2 00:00:00 ps
$ /bin/nice ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1013 4795 4793 0 75 0 - 1719 wait pts/2 00:00:00 bash
0 S 1013 4905 4795 0 75 0 - 1503 - pts/2 00:00:00 xterm
0 T 1013 5031 4795 0 76 0 - 3577 finish pts/2 00:00:00 emacs-x
0 R 1013 5040 4795 0 87 10 - 557 - pts/2 00:00:00 ps
$
1: /* 2: getpriority-pid.c -- 優先度の表示 3: ~yas/syspro/proc/getpriority-pid.c 4: Created on: 2009/12/14 12:15:11 5: */ 6: 7: #include <stdio.h> /* stderr, fprintf() */ 8: #include <sys/time.h> /* getpriority() */ 9: #include <sys/resource.h> /* getpriority() */ 10: #include <stdlib.h> /* strtol() */ 11: #include <limits.h> /* strtol() */ 12: 13: main( int argc, char *argv[] ) 14: { 15: int which, who, prio; 16: pid_t pid; 17: if( argc != 2 ) 18: { 19: fprintf(stderr,"Usage: %% %s pid\n",argv[0] ); 20: exit( 1 ); 21: } 22: pid = strtol( argv[1], NULL, 10 ); 23: prio = getpriority( PRIO_PROCESS, pid ); 24: printf("pid==%d, priority==%d\n", pid, prio); 25: }
$ echo $$
3788
$ ./getpriority-pid
Usage: % ./getpriority-pid pid
$ ./getpriority-pid $$
pid==3788, priority==0
$ ./getpriority-pid 0
pid==0, priority==0
$ nice -10 ./getpriority-pid 0
pid==0, priority==10
$ nice -20 ./getpriority-pid 0
pid==0, priority==19
$
$ ps -o state,uid,pid,ppid,rtprio,time,comm
S UID PID PPID RTPRIO TIME COMMAND
S 1013 4795 4793 - 00:00:00 bash
S 1013 4905 4795 - 00:00:00 xterm
T 1013 5031 4795 - 00:00:00 emacs-x
R 1013 5343 4795 - 00:00:00 ps
$
"-"
の表示は、実時間のプロセスではない。
linux-3.1.3/include/linux/sched.h 1220: struct task_struct { 1221: volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ ... 1233: int prio, static_prio, normal_prio; 1234: unsigned int rt_priority; 1235: const struct sched_class *sched_class; 1236: struct sched_entity se; 1237: struct sched_rt_entity rt; ... 1257: unsigned int policy; ... 1572: }; 1169: struct sched_entity { ... 1171: struct rb_node run_node; ... 1173: unsigned int on_rq; ... 1177: u64 vruntime; ... 1193: };struct task_struct の中に、struct sched_entity がある。
36: #define SCHED_NORMAL 0 37: #define SCHED_FIFO 1 38: #define SCHED_RR 2 39: #define SCHED_BATCH 3 40: /* SCHED_ISO: reserved but not implemented yet */ 41: #define SCHED_IDLE 5
linux-3.1.3/kernel/sys.c 233: /* 234: * Ugh. To avoid negative return values, "getpriority()" will 235: * not return the normal nice-value, but a negated value that 236: * has been offset by 20 (ie it returns 40..1 instead of -20..19) 237: * to stay compatible. 238: */ 239: SYSCALL_DEFINE2(getpriority, int, which, int, who) 240: { 241: struct task_struct *g, *p; 242: struct user_struct *user; 243: const struct cred *cred = current_cred(); 244: long niceval, retval = -ESRCH; 245: struct pid *pgrp; 246: 247: if (which > PRIO_USER || which < PRIO_PROCESS) 248: return -EINVAL; ... 252: switch (which) { 253: case PRIO_PROCESS: 254: if (who) 255: p = find_task_by_vpid(who); 256: else 257: p = current; 258: if (p) { 259: niceval = 20 - task_nice(p); 260: if (niceval > retval) 261: retval = niceval; 262: } 263: break; 264: case PRIO_PGRP: ... 275: case PRIO_USER: ... 293: } 294: out_unlock: ... 298: return retval; 299: } linux-3.1.3/include/linux/sched.h 1590: #define MAX_USER_RT_PRIO 100 1591: #define MAX_RT_PRIO MAX_USER_RT_PRIO 1592: 1593: #define MAX_PRIO (MAX_RT_PRIO + 40) 1594: #define DEFAULT_PRIO (MAX_RT_PRIO + 20) linux-3.1.3/kernel/sched.c 94: #define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) 95: #define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) 96: #define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio) ... 5016: int task_nice(const struct task_struct *p) 5017: { 5018: return TASK_NICE(p); 5019: } 5020: EXPORT_SYMBOL(task_nice);
linux-3.1.3/kernel/sched.c 1405: /* 1406: * Nice levels are multiplicative, with a gentle 10% change for every 1407: * nice level changed. I.e. when a CPU-bound task goes from nice 0 to 1408: * nice 1, it will get ~10% less CPU time than another CPU-bound task 1409: * that remained on nice 0. 1410: * 1411: * The "10% effect" is relative and cumulative: from _any_ nice level, 1412: * if you go up 1 level, it's -10% CPU usage, if you go down 1 level 1413: * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25. 1414: * If a task goes up by ~10% and another task goes down by ~10% then 1415: * the relative distance between them is ~25%.) 1416: */ 1417: static const int prio_to_weight[40] = { 1418: /* -20 */ 88761, 71755, 56483, 46273, 36291, 1419: /* -15 */ 29154, 23254, 18705, 14949, 11916, 1420: /* -10 */ 9548, 7620, 6100, 4904, 3906, 1421: /* -5 */ 3121, 2501, 1991, 1586, 1277, 1422: /* 0 */ 1024, 820, 655, 526, 423, 1423: /* 5 */ 335, 272, 215, 172, 137, 1424: /* 10 */ 110, 87, 70, 56, 45, 1425: /* 15 */ 36, 29, 23, 18, 15, 1426: }; ... 1768: static void set_load_weight(struct task_struct *p) 1769: { 1770: int prio = p->static_prio - MAX_RT_PRIO; 1771: struct load_weight *load = &p->se.load; ... 1782: load->weight = scale_load(prio_to_weight[prio]); 1783: load->inv_weight = prio_to_wmult[prio]; 1784: } linux-3.1.3/include/linux/sched.h 817: # define scale_load(w) (w)優先度 static_prio は、struct sched_entity se の se.load.weight とその逆数 se.load.inv_weight に反映される。se.load.{weight,inv_weight} の値は、 後に、vruntime の計算の重みづけに使われる。
名前 | 説明 |
---|---|
enqueue_task | プロセスが実行可能(runnable)になった |
dequeue_task | プロセスが実行可能ではなくなった |
yield_task | CPUを譲る。dequeueしてenqueue |
check_preempt_curr | 実行可能になった時にCPUを横取りすべきかをチェック |
pick_next_task | 次に実行すべきプロセスを選ぶ |
set_curr_task | スケジューリング・クラスが変更された |
task_tick | タイマ割込み(tick)の時に呼ばれる |
task_new | 新しいプロセスが生成された |
linux-3.1.3/kernel/sched.c 1786: static void enqueue_task(struct rq *rq, struct task_struct *p, int flags) 1787: { ... 1790: p->sched_class->enqueue_task(rq, p, flags); 1791: } 1793: static void dequeue_task(struct rq *rq, struct task_struct *p, int flags) 1794: { ... 1797: p->sched_class->dequeue_task(rq, p, flags); 1798: }
linux-3.1.3/kernel/sched.c 5050: static void 5051: __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio) 5052: { 5053: p->policy = policy; 5054: p->rt_priority = prio; 5055: p->normal_prio = normal_prio(p); 5056: /* we are holding p->pi_lock already */ 5057: p->prio = rt_mutex_getprio(p); 5058: if (rt_prio(p->prio)) 5059: p->sched_class = &rt_sched_class; 5060: else 5061: p->sched_class = &fair_sched_class; 5062: set_load_weight(p); 5063: } linux-3.1.3/include/linux/sched.h 1596: static inline int rt_prio(int prio) 1597: { 1598: if (unlikely(prio < MAX_RT_PRIO)) 1599: return 1; 1600: return 0; 1601: }
p->prio
の値に応じて
&rt_sched_class
か
&fair_sched_class
のどちらかを指す。
図? runqueueの構造
linux-3.1.3/kernel/sched.c 456: struct rq { ... 479: struct cfs_rq cfs; 480: struct rt_rq rt; ... 575: }; ... 312: struct cfs_rq { ... 322: struct rb_root tasks_timeline; 323: struct rb_node *rb_leftmost; 324: 325: struct list_head tasks; ... 381: }; ... 577: static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
図? runqueueの構造(red-black tree)
linux-3.1.3/kernel/sched_fair.c 352: static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) 353: { 354: struct rb_node **link = &cfs_rq->tasks_timeline.rb_node; 355: struct rb_node *parent = NULL; 356: struct sched_entity *entry; 357: int leftmost = 1; ... 362: while (*link) { 363: parent = *link; 364: entry = rb_entry(parent, struct sched_entity, run_node); ... 369: if (entity_before(se, entry)) { 370: link = &parent->rb_left; 371: } else { 372: link = &parent->rb_right; 373: leftmost = 0; 374: } 375: } ... 381: if (leftmost) 382: cfs_rq->rb_leftmost = &se->run_node; 383: 384: rb_link_node(&se->run_node, parent, link); 385: rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline); 386: } ... 318: static inline int entity_before(struct sched_entity *a, 319: struct sched_entity *b) 320: { 321: return (s64)(a->vruntime - b->vruntime) < 0; 322: }
&parent->rb_left
), 大きければ右(&parent->rb_right
) に進む。
cfs_rq->rb_leftmost
にも保存。
linux-3.1.3/kernel/sched.c 4102: void scheduler_tick(void) 4103: { 4104: int cpu = smp_processor_id(); 4105: struct rq *rq = cpu_rq(cpu); 4106: struct task_struct *curr = rq->curr; ... 4113: curr->sched_class->task_tick(rq, curr, 0); ... 4122: }
linux-3.1.3/kernel/sched_fair.c 4126: static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) 4127: { 4128: struct cfs_rq *cfs_rq; 4129: struct sched_entity *se = &curr->se; 4130: 4131: for_each_sched_entity(se) { 4132: cfs_rq = cfs_rq_of(se); 4133: entity_tick(cfs_rq, se, queued); 4134: } 4135: } 1206: static void 1207: entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) 1208: { ... 1212: update_curr(cfs_rq); ... 1238: } 558: static void update_curr(struct cfs_rq *cfs_rq) 559: { 560: struct sched_entity *curr = cfs_rq->curr; 561: u64 now = rq_of(cfs_rq)->clock_task; 562: unsigned long delta_exec; ... 572: delta_exec = (unsigned long)(now - curr->exec_start); ... 576: __update_curr(cfs_rq, curr, delta_exec); 577: curr->exec_start = now; ... 586: } 537: static inline void 538: __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr, 539: unsigned long delta_exec) 540: { 541: unsigned long delta_exec_weighted; ... 548: delta_exec_weighted = calc_delta_fair(delta_exec, curr); ... 550: curr->vruntime += delta_exec_weighted; 551: update_min_vruntime(cfs_rq); ... 556: }
図? 4つの要素を持つリスト構造
このリストを表現した二分探索木を1つ作り、節と枝(矢印)を用いて図示し なさい。ただし、木はバランスをしていなくても良いものとする。注意: 正しい二分探索木は、複数存在する。