6

There are several scheduling options in Linux, which can be set to a process with the help of a chrt command line. And I can't seem to grasp one of them... Which is SCHED_BATCH. In fact, it's description contradicts itself in several sources. But before, I'll summarize the facts I managed to get about all the scheduling options, as the different descriptions of SCHED_BATCH references them.

SCHED_FIFO and SCHED_RR are basically real-time scheduling policies, with slight differences, no questions here mostly, they are always run first before any other processes.

SCHED_OTHER is the default policy, relying on nice values of per process to assign priorities.

SCHED_DEADLINE - I haven't completely understood this one, it seems to be actually closer to SCHED_FIFO but with set timers of execution, and may actually preempt SCHED_FIFO/SCHED_RR tasks if those timers are reached.

SCHED_IDLE - basically "schedule only if otherwise the CPU would be idling", no questions here.

And now, there is SCHED_BATCH, which I found out that is quite controversial. On one hand, in the original implementations notes back from 2002 it is said it's basically the same as SCHED_IDLE for user code and SCHED_OTHER for kernel code (to avoid kernel resources lock-up due to a process never being scheduled). In the MAN articles though it is said it's basically the same as SCHED_OTHER but with a small penalty because it is considered CPU-bound.

Now, theese two SCHED_BATCH explanations are not coherent one with another. Which one is the truth? Did SCHED_BATCH got reimplemented somewhere along the way? Or someone misunderstood SCHED_BATCH when was writing the MAN article? Which of the explanations is the true one?

UPDATE: additional research:

I did some more digging, and found this kernel scheduler documentation, also by digging in the sched sources a bit it seems SCHED_BATCH is indeed handled by the same code as SCHED_OTHER.

There's still a test I did. I have a process which was actually throttling other processes because of it's high load even with nice 19, but default SCHED_OTHER setting. I've set it up as SCHED_IDLE, and the problem of the throttling of the other processes was gone... And then I decided to try out SCHED_BATCH for the same process (with the same nice 19 setting). And surprisingly enough, SCHED_BATCH also didn't throttle my other processes, like SCHED_IDLE!

But it seems from the docs I linked above, SCHED_IDLE may be also handled by the same code as SCHED_OTHER and SCHED_BATCH, but with super-low priority. Although I'm kinda still lost in which cases it does use CFS (which is SCHED_OTHER main implementation), and in which cases it uses the kernel/sched/idle.c implementation.

I definitely still don't have any conclusive answer, the tests and documentations are still not making too much sense to me. Tests showed that SCHED_BATCH worked like actually SCHED_IDLE would, but all documentation tells that it should work like SCHED_OTHER instead!

11
  • Noone knows anything?...
    – Evengard
    Nov 29, 2021 at 12:00
  • Two days may seem like a long time if you're holding your breath, but not a long time for someone to notice the question, understand it, and write up an answer. You've done the best you can by writing a well-researched question and applying a bounty. Be patient! :)
    – Jeff Schaller
    Nov 29, 2021 at 19:36
  • 2
    I haven't been watching this space, but is there controversy over the explanations, or confusion? My suggestion is to focus your post (title, introduction) on your actual question, which seems to me to be trying to understand the meaning of SCHED_BATCH.
    – Jeff Schaller
    Nov 29, 2021 at 19:40
  • 1
    I'm still not in a position to answer this question, but noticed your extra comments. They should definitely be part of your question, so that they're not missed by future potential answerers.
    – Jeff Schaller
    Dec 7, 2021 at 12:58
  • 1
    I just spent half a day searching the kernel source and I'm almost convinced that sched_batch may be deprecated but the documentation wasn't updated. "sched_batch" can be found in a few if() statements but there isn't a real code definition that I have found. Alt. Some very old discussions lead me to think it is basically sched_idle but able to preempt a sched_idle. (An idle cannot preempt another idle, they only get a turn when the scheduling timer comes around) sched_idle still uses the sched_normal RB-tree but equivalent to nice value 25.(not a true idle class to avoid possible deadlocks)
    – Max Power
    Jan 7 at 22:39

1 Answer 1

1

SCHED_BATCH

From man sched(7), about SCHED_BATCH:

…this policy will cause the scheduler to always assume that the thread is CPU-intensive. Consequently, the scheduler will apply a small scheduling penalty with respect to wakeup behavior, so that this thread is mildly disfavored in scheduling decisions.

Apparently, the CFS scheduler applies a "small penalty" to threads that are assumed to be CPU intensive. A look at the source code of Linux reveals that SCHED_BATCH affects the schedulers behavior in exactly one location. Namely kernel/sched/fair.c:yield_task_fair()

static void yield_task_fair(struct rq *rq)
{
    …
    if (curr->policy != SCHED_BATCH) {
        update_rq_clock(rq);
        /*
         * Update run-time statistics of the 'current'.
         */
        update_curr(cfs_rq);
        /*
         * Tell update_rq_clock() that we've just updated,
         * so we don't do microscopic update in schedule()
         * and double the fastpath cost.
         */
        rq_clock_skip_update(rq);
    }

    set_skip_buddy(se);
}

Judging from the functions names, it appears to be the function that yields, the current thread (and potentially selects the next thread). The thread currently running on the CPU (curr) is removed from CPU ("yielded"), to make the CPU available to another thread. If curr is running under the SCHED_BATCH scheduling policy, then some run-time statistics of curr are not updated.

I suspect not updating the stats leaves the thread CPU intensive from CFS' perspective, which, in turn, makes CFS less favorably select the thread.

SCHED_BATCH vs SCHED_IDLE

As for the difference between SCHED_BATCH and SCHED_IDLE: Both are actually very different. First, SCHED_IDLE threads are only run if there are idle CPUs. Hence there is no progress guarantee for SCHED_IDLE threads. If a system is 100% utilized with other threads, then SCHED_IDLE threads may never run. That is not the case for SCHED_BATCH threads, which participate in normal CPU-multiplexing, and hence are guranteed to progress.

Furthermore, with Linux >= 5.4, CPUs running SCHED_IDLE threads are considered idle from the CFS scheduler's perspective. That has an important implication: As soon as a non-SCHED_IDLE thread becomes runnable, the scheduler may immediately yield the SCHED_IDLE thread and place the non-SCHED_IDLE thread on it. See also "Fixing SCHED_IDLE" In: LWN.net (2019-11-26).

That SCHED_BATCH was also able to "unthrottle" your other tasks is probably just because the penalty that SCHED_BATCH threads receive was enough to do so. Furthermore, kernel/sched/idle.c is not directly related to SCHED_IDLE, this file just contains the scheduler-related code to put a CPU in idle mode. SCHED_OTHER, SCHED_BATCH and SCHED_IDLE are all scheduling policies of Linux's CFS scheduler (kernel/sched/fair.c).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .