🫠

LinuxのSCHED_BATCHスケジューリングは何をしているのか (補足)

2024/12/04に公開

はじめに

これは以前の記事(LinuxのSCHED_BATCHスケジューリングは何をしているのか) の補足です。まずはそちらを参照ください。ここでは6.12で追加された処理の影響について説明します。

6.12の変更

以前の記事は6.10の時点の情報でしたが6.12でEEVDFに対する様々な修正がマージされました: ML link
これによりSCHED_BATCHの動きは変わっていませんがwakeup時のNORMALタスクの動きに変更がありました(21コミット目)。これについて説明します。

まずEEVDFになったことによりCFSのときにあったユーザー調整可能なパラメータにも変更がありますが、今回のシリーズによりアプリケーション毎のslice長をsched_attrで指定することができるようになりました (22コミット目)。ざっくりといえばsliceが短い場合は一回の実行時間は短いものの一定時間内におけるスケジューリング回数が増えるためレスポンス性が向上します。もちろん短すぎると過剰なpreemptが発生してしまいますし、長すぎるとlatencyの増加につながるため適切な値を設定する必要があります。

さて21コミット目を見てみるとwakeup時にshorter sliceがlonger sliceをpreemptするような修正になっています。つまり短いスライスを持つタスクが(EEVDFのアルゴリズムとして次に実行されるタスクでなくとも)優先的に実行されるためここでもレスポンス性が向上します。

ここでこの判定が行われる箇所は前の記事で説明したwakeup時にタスクがSCHED_BATCHであるかどうかの判定の後になります。つまりwakeupしたタスクがSCHED_BATCHの場合はslice長の関係によらずそもそも他のプロセスをpreemptしません。コードとしてはこのあたりです: github link

/*
 * Preempt the current task with a newly woken task if needed:
 */
static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int wake_flags)
{
...
	/*
	 * BATCH and IDLE tasks do not preempt others.
	 */
	if (unlikely(!normal_policy(p->policy)))
		return;

	cfs_rq = cfs_rq_of(se);
	update_curr(cfs_rq);
	/*
	 * If @p has a shorter slice than current and @p is eligible, override
	 * current's slice protection in order to allow preemption.
	 *
	 * Note that even if @p does not turn out to be the most eligible
	 * task at this moment, current's slice protection will be lost.
	 */
	if (do_preempt_short(cfs_rq, pse, se) && se->vlag == se->deadline)
		se->vlag = se->deadline + 1;

(以前から変更のない処理ですが)上のif文でそもそもSCHED_BATCH(およびSCHED_IDLE)の場合は他のタスクをpreemptしないので何もせずにリターンします。下のif文が21コミット目で追加された箇所でwakeupしたタスクが実行中のタスクに比べて短いスライスかどうかをチェックし、その場合に現在のタスクのタスクがpreemptされるようにします(コメントを読むと必ずしも今wakeupしたタスクが次に実行されることは保証されないようです)。

おわりに

ということで「SCHED_BATCHのタスクはwakeupしたときに他のタスクをpreemptしない」という処理には変更がありませんがNORMALタスクのwakeup時の動きは6.12で変更がありました、という話でした。逆に言えば追加された処理を抑制するためにはSCHED_BATCHを指定すればよいです。

以上

Discussion