スケジューラについての調査 - オペレーティングシステム授業発表

66
スケジューラについての調査 2013/01/29 @amiq11

Upload: makoto-shimazu

Post on 24-May-2015

1.103 views

Category:

Engineering


2 download

TRANSCRIPT

Page 1: スケジューラについての調査 - オペレーティングシステム授業発表

スケジューラについての調査

2013/01/29@amiq11

Page 2: スケジューラについての調査 - オペレーティングシステム授業発表

はじめに

● いろいろなスケジューラの話をします

● 細かいこととか、技術的なことを tumblrに少しまとめてたりします

http://amiq11.tumblr.com

今回の分も きちんとまとめたいです

ここからいける

Page 3: スケジューラについての調査 - オペレーティングシステム授業発表

スケジューラとは

● 沢山仕事するときに、どれを実行するか選ぶための機構

– プロセス・スレッド =>タスク

● ハードウェアは決まっている

– 例えば、 CPUが 2コア 4スレッドとか

● NGパターン

– 飢餓状態 ( starvation )

● ずっとタスクが実行されないままになること

– IO boundなものと CPU boundなものの区別

● 同等だとどういうことになるか?

Page 4: スケジューラについての調査 - オペレーティングシステム授業発表

スケジューラの種類

● FIFO / RR

● O(1)

● CFS ( Completely Fair Scheduler )

● BFS ( Brain Fuck Scheduler )

● RM ( Rate Monotonic )

● DM ( Deadline Monotonic )

● EDF ( Earliest Deadline First )

● ポリシー

– システムコール sched_setschedulerで変更可

– man見て

Page 5: スケジューラについての調査 - オペレーティングシステム授業発表

O(1)

● kernel 2.6から

● 本とかはめっちゃある

– 詳解 Linuxカーネルとか

● タスクを優先度ごとのキュー (= runqueue,rq )に並べる

– active/expired

● →頭から一個取ってくるだけ O(1)

Page 6: スケジューラについての調査 - オペレーティングシステム授業発表

O(1)

● 静的優先順位 + 動的優先順位 (nice)

● 優先順位に応じて、実行できる時間が決まってる

● niceを決めるときには

– IO boundと CPU bound

– これまでの動きから予測する

Page 7: スケジューラについての調査 - オペレーティングシステム授業発表

CFS - 概要

● kernel 2.6.23から

● O(1)はややこしいし予測にも失敗する

● 単純に、「全てのタスクに同じ CPU時間」を割り当てる

● 実行時間: vruntime

– 理想的には全てのタスクの vruntimeは常に等しい

Page 8: スケジューラについての調査 - オペレーティングシステム授業発表

CFS - 概要

● 単純にタイムスライスを切って分ける

– cat /proc/sys/kernel/sched_latency_ns

– (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds) @fair.c l.36

– この期間中に1回は動く

Page 9: スケジューラについての調査 - オペレーティングシステム授業発表

CFS - 概要

● ただ、単純と言いつつ実はちょっと面倒なことをしている

– 眠っていたときの処理

● vruntimeを一番小さいやつに合わせる

– すぐ追いついちゃったときの処理

● unsigned int sysctl_sched_wakeup_granularity = 1000000UL;

– cat /proc/sys/kernel/sched_wakeup_granurarity_ns– next-buddy (preempt failure) / last-buddy (cache hot)ルール

– スライスしすぎちゃったときの処理

● min_granularity_ns

– cat /proc/sys/kernel/sched_min_granularity_ns– (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds)

@fair.c l.65

Page 10: スケジューラについての調査 - オペレーティングシステム授業発表

CFS – 実装

● 次のタスクを選ぶ関数

– pick_next_task

– スケジューリングクラスごとにある

static struct task_struct *pick_next_task_fair(struct rq *rq){

struct task_struct *p;struct cfs_rq *cfs_rq = &rq->cfs;struct sched_entity *se;

if (!cfs_rq->nr_running)return NULL;

do {se = pick_next_entity(cfs_rq);set_next_entity(cfs_rq, se);cfs_rq = group_cfs_rq(se);

} while (cfs_rq);

p = task_of(se);if (hrtick_enabled(rq))

hrtick_start_fair(rq, p);

return p;}

Page 11: スケジューラについての調査 - オペレーティングシステム授業発表

CFS – 実装

● 次のタスクを選ぶ関数

– pick_next_task

– スケジューリングクラスごとにある

● すっきりしてるけど闇は深いよ?

static struct task_struct *pick_next_task_fair(struct rq *rq){

struct task_struct *p;struct cfs_rq *cfs_rq = &rq->cfs;struct sched_entity *se;

if (!cfs_rq->nr_running)return NULL;

do {se = pick_next_entity(cfs_rq);set_next_entity(cfs_rq, se);cfs_rq = group_cfs_rq(se);

} while (cfs_rq);

p = task_of(se);if (hrtick_enabled(rq))

hrtick_start_fair(rq, p);

return p;}

Page 12: スケジューラについての調査 - オペレーティングシステム授業発表

CFS - 実装

● rqとかいいつつ赤黒木 (O(logn))

● キーは vruntime → 左端が一番動いてないやつ

● 赤黒木って?

– 赤黒木は平衡二分木のひとつ

– 黒の数が全ての経路で同じ ,赤は続かない

– 深さは一番差があるときで 2倍

– 回転はちょっと面倒

Page 13: スケジューラについての調査 - オペレーティングシステム授業発表

全体の実装

● スケジューラ全体の実装について

● 重要な構造体は以下

– task_struct→プロセスの情報管理

– sched_xx_entity

● →xx = なし (CFS) / rt (FIFO/RR) / dl (DEADLINE)

→xxに対応したスケジューラの情報管理 (vruntimeとか )– sched_class→スケジューラのポリシー自体

● 関数ポインタ群

Page 14: スケジューラについての調査 - オペレーティングシステム授業発表

全体の実装

● task_struct

– タスクに関する情報

– 4kB近くあったり

struct task_struct {volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */void *stack;atomic_t usage;unsigned int flags; /* per process flags, defined below */unsigned int ptrace;int prio, static_prio, normal_prio;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;struct sched_dl_entity dl;pid_t pid;pid_t tgid;struct timespec start_time; /* monotonic time */struct timespec real_start_time; /* boot based time */struct css_set __rcu *cgroups;

Page 15: スケジューラについての調査 - オペレーティングシステム授業発表

全体の実装

● task_struct

– タスクに関する情報

– 4kB近くあったり

struct task_struct {volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */void *stack;atomic_t usage;unsigned int flags; /* per process flags, defined below */unsigned int ptrace;int prio, static_prio, normal_prio;const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt;struct sched_dl_entity dl;pid_t pid;pid_t tgid;struct timespec start_time; /* monotonic time */struct timespec real_start_time; /* boot based time */struct css_set __rcu *cgroups;

int pdeath_signal; /* The signal sent when the parent dies */unsigned int jobctl; /* JOBCTL_*, siglock protected *//* ??? */unsigned int personality;unsigned did_exec:1;unsigned in_execve:1; /* Tell the LSMs that the process is doing an

* execve */

Page 16: スケジューラについての調査 - オペレーティングシステム授業発表

全体の実装

● sched_entity

– 各種のスケジューリングクラスに対応したデータを保持

struct sched_entity {struct load_weight load; /* for load-balancing */struct rb_node run_node;struct list_head group_node;unsigned int on_rq;

u64 exec_start;u64 sum_exec_runtime;u64 vruntime;u64 prev_sum_exec_runtime;

u64 nr_migrations;

#ifdef CONFIG_SCHEDSTATSstruct sched_statistics statistics;

#endif

#ifdef CONFIG_FAIR_GROUP_SCHEDstruct sched_entity *parent;/* rq on which this entity is (to be) queued: */struct cfs_rq *cfs_rq;/* rq "owned" by this entity/group: */struct cfs_rq *my_q;

#endif};

Page 17: スケジューラについての調査 - オペレーティングシステム授業発表

全体の実装

● sched_xx_class

– dl_sched_class

const struct sched_class dl_sched_class = {.next = &rt_sched_class,.enqueue_task = enqueue_task_dl,.dequeue_task = dequeue_task_dl,.yield_task = yield_task_dl,

.check_preempt_curr = check_preempt_curr_dl,

.pick_next_task = pick_next_task_dl,

.put_prev_task = put_prev_task_dl,

#ifdef CONFIG_SMP.select_task_rq = select_task_rq_dl,

.set_cpus_allowed = set_cpus_allowed_dl,

.rq_online = rq_online_dl,

.rq_offline = rq_offline_dl,

.pre_schedule = pre_schedule_dl,

.post_schedule = post_schedule_dl,

.task_woken = task_woken_dl,#endif

.set_curr_task = set_curr_task_dl,

.task_tick = task_tick_dl,

.task_fork = task_fork_dl,

.task_dead = task_dead_dl,

.prio_changed = prio_changed_dl,

.switched_from = switched_from_dl,

.switched_to = switched_to_dl,};

Page 18: スケジューラについての調査 - オペレーティングシステム授業発表

実装● リスト構造

● pick_next_taskあたりを見るとタスクをどう選ぶかわかりやすい

Page 19: スケジューラについての調査 - オペレーティングシステム授業発表

実装● リスト構造

● pick_next_taskあたりを見るとタスクをどう選ぶかわかりやすい

● schedule()を呼ぶと次のタスクを選ぶ

static inline struct task_struct *pick_next_task(struct rq *rq){

const struct sched_class *class;struct task_struct *p;

/* * Optimization: we know that if all tasks are in * the fair class we can call that function directly: */if (likely(rq->nr_running == rq->cfs.h_nr_running)) {

p = fair_sched_class.pick_next_task(rq);if (likely(p))

return p;}

for_each_class(class) {p = class->pick_next_task(rq);if (p)

return p;}

BUG(); /* the idle class will always have a runnable task */}

Page 20: スケジューラについての調査 - オペレーティングシステム授業発表

全体の実装

● hrtick

– high resolution tick

– 全体の tick( .configで HZ

として定義 )と異なる

– 10us制限あり

– 時間が来ると scheduleを起こす

static struct task_struct *pick_next_task_fair(struct rq *rq){

struct task_struct *p;struct cfs_rq *cfs_rq = &rq->cfs;struct sched_entity *se;

if (!cfs_rq->nr_running)return NULL;

do {se = pick_next_entity(cfs_rq);set_next_entity(cfs_rq, se);cfs_rq = group_cfs_rq(se);

} while (cfs_rq);

p = task_of(se);if (hrtick_enabled(rq))

hrtick_start_fair(rq, p);

return p;}

Page 21: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた - 方法

● 評価方法

– 右のようなプログラム (load.c)を用意する

– これの優先順位を適当にいじったときの、タスクのスイッチングを確認する

– 確認には trace-cmdを使う

● trace-cmd record -e sched_switch● traceって ?

– カーネルが提供するログ– mount -t debugfs nobody /proc/sys/debug– cat /proc/sys/debug/tracing/trace

– kernelsharkを用いて表示

● まず1コア1スレッドの仮想マシン (kvm)上で動かす

– 3.7.0-rc6-sched-deadline-mainline-dl

#include <stdio.h>void main( void ){ volatile int i = 0; printf( "Load Program\n" ); printf( "Start!\n" ); while ( 1 ) i++;

}

Page 22: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた CFS

● CFS x3 niceは 10

Page 23: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた CFS

● CFS x3 nice が 5/10/15

– CFSにおける nice → vruntimeの重み付け (1につき 1.25 → 倍 1.25^5 = 3.05)

Page 24: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた CFS

● 普段の状況はこんな感じ

Page 25: スケジューラについての調査 - オペレーティングシステム授業発表

CFS

● CFSを大学生に例えると ...?

● 状況 

– OSの発表

– と BDM ( ★ ☆ びっくり どっきり メカ )

– と実験レポ

– と試験勉強をしないといけない

Page 26: スケジューラについての調査 - オペレーティングシステム授業発表

CFS

● とりあえずOSの発表準備する

● ある程度進めた後、違うタスクを始める

● とりあえず BDMの準備する

● ある程度進めた後、違うタスクを始める

● …

Page 27: スケジューラについての調査 - オペレーティングシステム授業発表

CFS

● 発表当日

進捗は・・・

● OSの準備 50%

● BDMの準備 50%

● 実験レポの準備 50%

● 試験勉強 50%

Page 28: スケジューラについての調査 - オペレーティングシステム授業発表

実時間 (RealTime)

● 発表に間に合ってない!!!!

– けど試験勉強も進んでる

● なぜ?

– 締め切りの存在

– 締め切りがあるようなタスクには不向き

● ロボットの制御など

– マップの更新 /モータの制御 (1msごと /10msごととか )

– 逆に画像を用いた補正などはゆっくりでいい

Page 29: スケジューラについての調査 - オペレーティングシステム授業発表

実時間

● ロボットだとどういう感じか

– 10msに一度

● センサ情報の更新  (例:速度 v)● 自分の位置の計算 (例: pos=∫vdt)● モータ出力の更新 (例: V( 電圧) = A*dif)

– カメラからの画像がとれたら

● 自己位置の補正

● モータ出力が遅れると?

– 例:画像処理が遅くて固まる

Page 30: スケジューラについての調査 - オペレーティングシステム授業発表

FIFO/RR

● じゃあ先にやるべきものをとりあえずやってしまおう

● 最も原始的

● FIFOはキューの頭のやつを終わるまでやる

● RRは優先度が同じやつを決まった時間 (time slice)ごとにかわりばんこにやる

Page 31: スケジューラについての調査 - オペレーティングシステム授業発表

FIFO/RR

● 例えばさっきの例で言えば ...

● 先にOSの発表準備を終わらせる

● 終わったら実験レポも終わらせる

● その次に BDMを完成

● 最後に試験勉強

Page 32: スケジューラについての調査 - オペレーティングシステム授業発表

FIFO/RR

● ダメな点 1

– 簡単に飢餓

● ダメな点 2

– じつは上手に終わらない例がある

Page 33: スケジューラについての調査 - オペレーティングシステム授業発表

FIFO/RR

● 例えば、OSの発表の準備中に急にサークルの友人から電話がかかってくる

– 「回路製作の締め切りが日曜になりました!よろしく!!!」

● でも自分はすでにOSの発表準備をしている

Page 34: スケジューラについての調査 - オペレーティングシステム授業発表

FIFO/RR

● 例えば、OSの発表の準備中に急にサークルの友人から電話がかかってくる

– 「回路製作の締め切りが日曜になりました!よろしく!!!」

● でも自分はすでにOSの発表準備をしている

よって無視

● ” ”適切に優先順位を指定してやれば 大丈夫

– 予め全ての優先順位が決まってないと難しい

● 同じなら

– FIFO:とりあえず先にやってるものが終わるまでは次に移れない

– RR:交代に進めるけど、時間は半々

☆実際には後輩に任せました -(ゝω・ )b

Page 35: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた FIFO/RR

● RR + CFS prio 1 + nice10

● /proc/sys/kernel/sched_rt_period_us → 1s/proc/sys/kernel/sched_rt_runtime_us → 0.95s

Page 36: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた FIFO/RR

● RR(same) x2 prio 50

Page 37: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた FIFO/RR

● FIFO(same) x2 prio 50

– 飢餓状態!!!

Page 38: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた FIFO/RR

● RR(higher) + RR(lower) prio 49(pid 2260)/51(pid 2261)

– 飢餓状態!!!

Page 39: スケジューラについての調査 - オペレーティングシステム授業発表

– 実際に使ってみた FIFO/RR

● 実際に RRを動かしてみよう

● 0.05sしか割り当ててもらえない辛さ

● コマンド

– schedtool -R -p 1 -e ./load &

– trace-cmd record -e sched_switch

– killall -KILL load

– kernelshark

Page 40: スケジューラについての調査 - オペレーティングシステム授業発表

RM/DM

● RM → 周期が短いものから実行

● DM → “ ”相対 デッドラインが短いものから実行

● 相対デッドライン ( relative deadline )

● 絶対デッドライン ( absolute deadline )

Page 41: スケジューラについての調査 - オペレーティングシステム授業発表

RM/DM

● 固定優先度と動的優先度

– fixed priority / dynamic priority

● RMも DMも固定優先度

→予め優先順位が決まる

● RMは特に組み込みでよく使われる

● けっこうデッドライン守れる

– ほとんどの組み合わせで CPU使用率 80%くらいはいけるらしい

Page 42: スケジューラについての調査 - オペレーティングシステム授業発表

EDF - 概要

● 一番いいスケジューリングってなんだろう?

→一番締め切りが近いものからやる

● EDF ( Earliest Deadline First )

Page 43: スケジューラについての調査 - オペレーティングシステム授業発表

EDF - 概要

● EDFと RMの比較

● T1:period=4 runtime=1

● T2:period=6 runtime=2

● T3:period=8 runtime=3

● CPU usage =

1/4+2/6+3/8=95.8%

Page 44: スケジューラについての調査 - オペレーティングシステム授業発表

EDF - 概要

● メリット

– CPU使用率が 100%になるまではデッドラインを守れる

● デメリット

– CPU使用率が 100%を超えた時にドミノ倒し現象が起こる

ex. )明日締め切りなのに明後日までかかったら明後日締め切りのタスクは終わらない

– 動的に優先度を変えるために実装が (RM比で )かなり面倒

● あまり普及していない

– マルチコアでは最適でなくなる

Page 45: スケジューラについての調査 - オペレーティングシステム授業発表

EDF – 応答時間

● EDFってどれくらいの時間でタスクを完了するんだろう?

→締め切りを守れるにしても、どれくらい時間かかるの?

Page 46: スケジューラについての調査 - オペレーティングシステム授業発表

EDF – 応答時間

● 1 CPU

● CPUバウンド (IO待ちで寝たりしない )

● いつでもプリエンティブ

● 任意の時刻にタスクが現れる

● 相対デッドラインは、実行時間以上の任意の値を取る

● 相対デッドラインは実行時間に比例

● タスクの到着間隔の平均・実行時間の平均は既知

● この条件で、到着間隔と実行時間が指数分布という仮定

Page 47: スケジューラについての調査 - オペレーティングシステム授業発表

EDF – 応答時間

● 興味ある人は参考資料を見てください!!

● 条件がハマれば良さそう

● 到着間隔 /実行時間が指数分布と置くのは正しい?

Page 48: スケジューラについての調査 - オペレーティングシステム授業発表

EDF – 実装

● githubに EDFを実装したものが落ちてる

● https://github.com/jlelli/sched-deadline

● kernel-3.7.0-rc6+

Page 49: スケジューラについての調査 - オペレーティングシステム授業発表

EDF – 実装

● とりあえず pick_next_task_dlを見てみる

● すると、以下がキモっぽいdl_se = pick_next_dl_entity(rq, dl_rq);

● これは右のようになっている

● 要するに赤黒木

– キーは絶対デッドライン時刻static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq,

struct dl_rq *dl_rq){

struct rb_node *left = dl_rq->rb_leftmost;

if (!left)return NULL;

return rb_entry(left, struct sched_dl_entity, rb_node);}

Page 50: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● これの実装では、パラメータは以下の3つ

– deadline - 締め切り

– runtime - 走ることの出来る時間

– period - タスクの周期

Page 51: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● sched_setscheduler2とやらを呼べって書いてある

● →呼んでみた

● 呼んでみた・・・

#include <sys/types.h>#include <unistd.h>#include <linux/sched.h>#include <sched.h>#include <stdlib.h>

int main( int argc __attribute__((unused)), char *argv[] __attribute__((unused)) ){ pid_t mypid = getpid(); struct sched_param2 sched_status = { .sched_priority = 1 .sched_runtime = 10000, .sched_deadline = 100000, .sched_period = 100000 }; if ( sched_setscheduler2( mypid, SCHED_DEADLINE, &sched_status ) ) { perror( "sched_setscheduler2" ); return 1; }

volatile int i=0; while( 1 ) i++; return 0;}

Page 52: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● sched_setscheduler2とやらを呼べって書いてある

● →呼んでみた

#include <sys/types.h>#include <unistd.h>#include <linux/sched.h>#include <sched.h>#include <stdlib.h>

int main( int argc __attribute__((unused)), char *argv[] __attribute__((unused)) ){ pid_t mypid = getpid(); struct sched_param2 sched_status = { .sched_priority = 1 .sched_runtime = 10000, .sched_deadline = 100000, .sched_period = 100000 }; if ( sched_setscheduler2( mypid, SCHED_DEADLINE, &sched_status ) ) { perror( "sched_setscheduler2" ); return 1; }

volatile int i=0; while( 1 ) i++; return 0;}

dame.c: In function ‘main’:dame.c:15: error: variable ‘sched_status’ has initializer but incomplete typedame.c:16: error: unknown field ‘__sched_priority’ specified in initializerdame.c:17: error: request for member ‘sched_flags’ in something not a structure or uniondame.c:18: warning: excess elements in struct initializerdame.c:18: warning: (near initialization for ‘sched_status’)dame.c:15: error: storage size of ‘sched_status’ isn’t known

 _人人人人人人人人_ > 突然のエラー <  ̄ Y^Y^Y^Y^Y^Y^Y ̄

Page 53: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● でもソースには関数あるし・・・

● 動かない理由がわからない

● わからない・・・

● そして溶けていった数日間

int sched_setscheduler2(struct task_struct *p, int policy, const struct sched_param2 *param2)

{return __sched_setscheduler(p, policy, param2, true);

}

カーネルコンパイル周りでサークルの先輩にめっちゃ助けてもらいました・・・

Page 54: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

まさか ?

Page 55: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● schedtoolを使ったら動いた

– 何で?システムコールが定義されてるって書いてあったけど・・・?

Page 56: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● schedtoolを使ったら動いた

– 何で?システムコールが定義されてるって書いてあったけど・・・?

● システムコールとは

– じつは割り込み (0x80番 )

– 引数はスタックではなくレジスタ

– eaxに種別をセット

● exitなら 1, writeなら 4など

● schedtoolは右のようなマクロを自分で定義していた

#ifdef __i386__#define __NR_sched_setparam2 350#define __NR_sched_getparam2 351#define __NR_sched_setscheduler2 352#endif

#define sched_setscheduler2(pid, policy, param) \ syscall(__NR_sched_setscheduler2, pid, policy, param)

#define sched_getparam2(pid, param) \ syscall(__NR_sched_getparam2, pid, param)

#define sched_setparam2(pid, param) \ syscall(__NR_sched_setparam2, pid, param)

tags/v4だと ,349,350,351と      1少なくする必要あり

Page 57: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみた

● EDF x1 runtime=10ms / deadline=100ms/ period=100ms

● 達成・・・して・・・なくね・・・?

Page 58: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみれなかった

● sched_class的には dl_sched_classは rtより高い

– つまり誰からも干渉を受けず、自分のしごとを淡々とこなすはず

– 本来なら下図のようになるはず

● でもどうも途中で切れてるように見える

– trace-cmd のせい? (うまく traceできてない可能性)

– preemption周りにバグ?(他のタスクが preemptしたときにスルーできない)

Page 59: スケジューラについての調査 - オペレーティングシステム授業発表

実際に使ってみれなかった

● やりたかったこと

– 1コアで

● EDF + CFS● EDF + RR● EDF x2(間に合う )● EDF x2( 間に合わない )● EDF x1( 1ms 周期 )

– 今度は2コア2スレッド

● EDF x2 ( 間に合う )● EDF x3 ( それぞれ CPU時間 2/3 )

– マルチコアのときには CPU100%は保証できない

● からどうしたらいいか?● という結論を導いて、もうすこし考察を深めたかった

Page 60: スケジューラについての調査 - オペレーティングシステム授業発表

まとめ

● CFSスケジューラは優秀

– 普通に使っている分には違和感を感じることはない

● EDFスケジューラはリアルタイム性が欲しいときに有効な手段

– だけどうまく実装されている例があまりない

– 動くようにしてみたいですね

● 意外と idleしている時間って多い

● linuxカーネルの広がる闇

– わからないことをしらべたらわからないからしらべたら (以下 n回続く)

– CONFIG_SMP(マルチコア対応部分 )がかなりある

– わからないことが多すぎて時間が食いつぶされてしまいました・・・

Page 61: スケジューラについての調査 - オペレーティングシステム授業発表

おまけ - main

● スケジューラの元ってどこ

● nohzとか hrtickとか ,SMPとかそうじゃないとか ,同じような関数でも違うやつがいろいろあって難しかった

● →コンパイル時のオプション

● ソースの感じでは hrtickとして動くっぽい

… … いろいろたどる 

● kernelの一番大元にいきついた

– arch/x86/kernel/head32.c i386_start_kernel()とか

– 疑問:これの上はどこ?

amiq@ostest> grep NO_HZ /boot/config-3.7.0-rc6+ CONFIG_NO_HZ=yamiq@ostest> grep HRTICK /boot/config-3.7.0-rc6+ CONFIG_SCHED_HRTICK=y

Page 62: スケジューラについての調査 - オペレーティングシステム授業発表

おまけ - main

● i386_start_kernel

● →start_kernel(init/main.c)

– dmesgの最初はここから

● → sched_init

– init_hrtick->hrtimer_init

● → tick_init

– tick_notifier構造体の登録

– → … …数層の関数ジャンプ

● → tick_periodic– do_timer → jiffies/xtimeの変更とかしてる中枢

Page 63: スケジューラについての調査 - オペレーティングシステム授業発表

おまけ - main

● start_kernel → init_timers → open_softirq

● run_timer_softirq → hrtimer_run_pending → hrtimer_switch_to_hres → tick_setup_sched_timer

● ここで tick_sched_timerの準備をしてる

/* * linux/init/main.c * * Copyright (C) 1991, 1992 Linus Torvalds *

... */

[ 0.000000] hpet clockevent registered[ 0.000000] tsc: Detected 2393.996 MHz processor[ 0.008000] Calibrating delay loop (skipped) preset value.. 4787.99 BogoMIPS (lpj=9575984)

Page 64: スケジューラについての調査 - オペレーティングシステム授業発表

おまけ - main

● tick_sched_timerか tick_periodic → update_process_times(user_mode(regs));

● からの scheduler_tick

● ここでやっと schedulerに戻ってきた

● これが HZごとに実行されるらしい

– HZを使ってるところは見つからなかった・・・ ??

/* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. */void scheduler_tick(void){

int cpu = smp_processor_id();struct rq *rq = cpu_rq(cpu);struct task_struct *curr = rq->curr;

sched_clock_tick();

raw_spin_lock(&rq->lock);update_rq_clock(rq);update_cpu_load_active(rq);curr->sched_class->task_tick(rq, curr, 0);raw_spin_unlock(&rq->lock);

perf_event_task_tick();

#ifdef CONFIG_SMPrq->idle_balance = idle_cpu(cpu);trigger_load_balance(rq, cpu);

#endif}

Page 65: スケジューラについての調査 - オペレーティングシステム授業発表

おまけ - タスクスイッチ

● タスクの切り替えってどうやってるの?

– PCとか、各種レジスタの退避とかスタックポインタとか

– 関数ジャンプならスタックに積むだけだけど・・・

● switch_toマクロ

– /arch/x86/include/asm/switch_to.h

Page 66: スケジューラについての調査 - オペレーティングシステム授業発表

● flags/EBP/ESPを保存して、データを引っ張ってくる

● レジスタはスタックにある

● __switch_toで切り替え

● スタックポインタとかは構造体のメンバとして保存

#define switch_to(prev, next, last) \do { \

/* \ * Context-switching clobbers all registers, so we clobber \ * them explicitly, via unused output variables. \ * (EAX and EBP is not listed because EBP is saved/restored \ * explicitly for wchan access and EAX is the return value of \ * __switch_to()) \ */ \unsigned long ebx, ecx, edx, esi, edi; \

\asm volatile("pushfl\n\t" /* save flags */ \

"pushl %%ebp\n\t" /* save EBP */ \ "movl %%esp,%[prev_sp]\n\t" /* save ESP */ \ "movl %[next_sp],%%esp\n\t" /* restore ESP */ \ "movl $1f,%[prev_ip]\n\t" /* save EIP */ \ "pushl %[next_ip]\n\t" /* restore EIP */ \ __switch_canary \ "jmp __switch_to\n" /* regparm call */ \ "1:\t" \ "popl %%ebp\n\t" /* restore EBP */ \ "popfl\n" /* restore flags */ \

\ /* output parameters */ \ : [prev_sp] "=m" (prev->thread.sp), \ [prev_ip] "=m" (prev->thread.ip), \ "=a" (last), \

\ /* clobbered output registers: */ \ "=b" (ebx), "=c" (ecx), "=d" (edx), \ "=S" (esi), "=D" (edi) \ \ __switch_canary_oparam \

\ /* input parameters: */ \ : [next_sp] "m" (next->thread.sp), \ [next_ip] "m" (next->thread.ip), \ \ /* regparm parameters for __switch_to(): */ \ [prev] "a" (prev), \ [next] "d" (next) \

\ __switch_canary_iparam \

\ : /* reloaded segment registers */ \

"memory"); \} while (0)

おまけ - タスクスイッチ