Introduction to workqueue

25
Workqueueの話 2014/3/28 109回、カーネル読書会

description

 

Transcript of Introduction to workqueue

Page 1: Introduction to workqueue

Workqueueの話2014/3/28第109回、カーネル読書会

Page 2: Introduction to workqueue

あなたは誰ですか?

● 吉田 茂● ミラクル・リナックス● Linuxサポートエンジニア● カーネル素人

Page 3: Introduction to workqueue

最初の貢献

commit 0515973ffb16c2852a1bb1df2ca1456556faaaa5Author: Shigeru Yoshida <[email protected]>Date: Sun Nov 17 12:12:36 2013 +0900

sched: Fix a trivial typo in comments

Fix a trivial typo in rq_attach_root().

Signed-off-by: Shigeru Yoshida <[email protected]> Signed-off-by: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/20131117.121236.1990617639803941055.shigeru.y Signed-off-by: Ingo Molnar <[email protected]>

Page 4: Introduction to workqueue

最初の貢献

diff --git a/kernel/sched/core.c b/kernel/sched/core.cindex a1591ca..718730d 100644--- a/kernel/sched/core.c+++ b/kernel/sched/core.c@@ -4762,7 +4762,7 @@ static void rq_attach_root(struct rq *rq, struct root_doma cpumask_clear_cpu(rq->cpu, old_rd->span);

/*- * If we dont want to free the old_rt yet then+ * If we dont want to free the old_rd yet then * set old_rd to NULL to skip the freeing later * in this function: */

Page 5: Introduction to workqueue

Concurrency Managed Workqueue

● プロセスコンテキストで非同期に処理を実行● 処理(コールバック関数)をキューに登録● ワーカスレッドがキューに登録された処理を実

Page 6: Introduction to workqueue

従来のWorkqueue

w0

w1

w2

10ms5ms 5ms

10ms5ms

10ms5ms

50ms

スレッド数=1

Documentation/workqueue.txt

Page 7: Introduction to workqueue

CPUが遊ぶ

w0

w1

w2

10ms5ms 5ms

10ms5ms

10ms5ms

50ms

スレッド数=1

Page 8: Introduction to workqueue

Concurrency Managed Workqueue

w0

w1

w2

10ms5ms 5ms

10ms5ms

10ms5ms

25ms

スレッド数>=3

Page 9: Introduction to workqueue

スレッドプール

ThreadThread

Thread

Thread Thread

CPU

Job Queue Thread Pool

CPUスケジューラ

ジョブスケジューラ

Page 10: Introduction to workqueue

スレッドプールの悩みどころ

● より多くのJobを受け入れる

→スレッドが増えオーバヘッドが増える

● スレッドの数を制限する

→CPUが遊ぶ

● どのくらいのスレッド数にするか?

→動的にがんばる

Page 11: Introduction to workqueue

2段スケジューラ

ThreadThread

Thread

Thread Thread

CPU

Job Queue Thread Pool

CPUスケジューラ

ジョブスケジューラ

カーネル

ユーザ(ライブラリ)

Page 12: Introduction to workqueue

すべてはカーネルが知っている

ThreadThread

Thread

Thread Thread

CPU

Job Queue Thread Pool

CPUスケジューラ

ジョブスケジューラ

全部カーネル!!

Page 13: Introduction to workqueue

APIを読む(1/2)struct work_struct {

atomic_long_t data;struct list_head entry;work_func_t func;

};

schedule_work(struct work_struct *work)-> queue_work(system_wq, work) -> queue_work_on(WORK_CPU_UNBOUND, wq, work) -> __queue_work(cpu, wq, work) -> insert_work(pwq, work, worklist, work_flags)

Page 14: Introduction to workqueue

APIを読む(2/2)static void insert_work(struct pool_workqueue *pwq,

struct work_struct *work, struct list_head *head,unsigned int extra_flags)

{struct worker_pool *pool = pwq->pool;set_work_pwq(work, pwq, extra_flags);list_add_tail(&work->entry, head); // キューにつなぐ

get_pwq(pwq);

smp_mb();

if (__need_more_worker(pool))wake_up_worker(pool); // ワーカスレッドを起こす

}

Page 15: Introduction to workqueue

ワーカスレッドを読む(1/4)static int worker_thread(void *__worker){

struct worker *worker = __worker;struct worker_pool *pool = worker->pool;// ワーカスレッドには特別なフラグを立てる

worker->task->flags |= PF_WQ_WORKER;

woke_up:spin_lock_irq(&pool->lock);

if (unlikely(worker->flags & WORKER_DIE)) {spin_unlock_irq(&pool->lock);worker->task->flags &= ~PF_WQ_WORKER;return 0;

}worker_leave_idle(worker); // idleスレッドの数を数える

Page 16: Introduction to workqueue

ワーカスレッドを読む(2/4)recheck:

if (!need_more_worker(pool))goto sleep;

if (unlikely(!may_start_working(pool)) && manage_workers(worker))goto recheck;

worker_clr_flags(worker, WORKER_PREP | WORKER_REBOUND);

Page 17: Introduction to workqueue

ワーカスレッドを読む(3/4)do {

struct work_struct *work =list_first_entry(&pool->worklist,

struct work_struct, entry);

if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {// ?????

/* optimization path, not strictly necessary */process_one_work(worker, work);if (unlikely(!list_empty(&worker->scheduled)))

process_scheduled_works(worker);} else {

move_linked_works(work, &worker->scheduled, NULL);process_scheduled_works(worker);

}} while (keep_working(pool));

worker_set_flags(worker, WORKER_PREP, false);

Page 18: Introduction to workqueue

ワーカスレッドを読む(4/4)sleep:

if (unlikely(need_to_manage_workers(pool)) && manage_workers(worker))goto recheck;

worker_enter_idle(worker); // idleスレッドの数を数える

// スリープ

__set_current_state(TASK_INTERRUPTIBLE);spin_unlock_irq(&pool->lock);schedule();goto woke_up; // 起床したら関数のはじめへ

}

Page 19: Introduction to workqueue

CPUスケジューラを読む

static void __sched __schedule(void){... // 変数宣言

need_resched:preempt_disable();cpu = smp_processor_id();rq = cpu_rq(cpu);rcu_note_context_switch(cpu);prev = rq->curr; // 現在のプロセスを選択

if (sched_feat(HRTICK))hrtick_clear(rq);

Page 20: Introduction to workqueue

CPUスケジューラを読む(1/3)smp_mb__before_spinlock();raw_spin_lock_irq(&rq->lock);

switch_count = &prev->nivcsw;if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {

if (unlikely(signal_pending_state(prev->state, prev))) {prev->state = TASK_RUNNING;

} else {deactivate_task(rq, prev, DEQUEUE_SLEEP);prev->on_rq = 0;if (prev->flags & PF_WQ_WORKER) {

struct task_struct *to_wakeup;to_wakeup = wq_worker_sleeping(prev, cpu);if (to_wakeup)

try_to_wake_up_local(to_wakeup);}

}switch_count = &prev->nvcsw;

}

Page 21: Introduction to workqueue

CPUスケジューラを読む(2/3)pre_schedule(rq, prev);

if (unlikely(!rq->nr_running))idle_balance(cpu, rq);

put_prev_task(rq, prev);next = pick_next_task(rq); // 次のプロセスを選択

clear_tsk_need_resched(prev);rq->skip_clock_update = 0;

if (likely(prev != next)) {rq->nr_switches++;rq->curr = next;++*switch_count;context_switch(rq, prev, next); // コンテキストスイッチ

cpu = smp_processor_id();rq = cpu_rq(cpu);

} elseraw_spin_unlock_irq(&rq->lock);

Page 22: Introduction to workqueue

CPUスケジューラを読む(3/3)

post_schedule(rq);sched_preempt_enable_no_resched();if (need_resched())

goto need_resched;}

Page 23: Introduction to workqueue

まとめ

ThreadThread

Thread

Thread Thread

CPU

Workqueue Thread Pool

①work(仕事)をリストに追加

②ワーカスレッドがwork(仕事)をこなす

③ワーカスレッドがスリープ

④次のワーカスレッドにバトンタッチ!!

Page 24: Introduction to workqueue

最後に…

『詳解Linuxカーネル 第3版』 2007, v2.6.11

『Linuxカーネル2.6解読室』 2006, v2.6.15

『Linux Kernel Architecture』 2008, v2.6.24

『Linux Kernel Development』 2010, v2.6.34

Page 25: Introduction to workqueue

おしまい