Linux process scheduling-complete Fair dispatch class __linux

Source: Internet
Author: User

Fully fair scheduling class is an example of scheduling class

static const struct Sched_class Fair_sched_class = {
    . Next           = &idle_sched_class,
    . Enqueue_task       = Enqueue_task_fair,
    . Dequeue_task       = Dequeue_task_fair,
    . Yield_task     = Yield_task_fair,

    . Check_ Preempt_curr = Check_preempt_wakeup,

    . Pick_next_task     = Pick_next_task_fair,
    . Put_prev_task      = Put_prev_task_fair,


    . Set_curr_task          = Set_curr_task_fair,.
    Task_tick      = Task_tick_fair,
    . Task_new       = Task_new_fair,
};

A fully fair scheduling class or a function of a real-time scheduling class is invoked in the main scheduler and in the cycle scheduler according to the process type.

@next, point to the Idle scheduling class, and next to the real-time scheduling class points to the fully fair dispatch class. This order has been established before compiling and will not be created dynamically during system runtime.

@enqueue_task_fair, a new process is added to the ready queue, which occurs when the process changes from sleep state to a running state.

@dequeue_task, removes a process from the ready queue, which occurs when the process switches from a running state to a state that is not running. Although this is called a queue, the internal implementation is entirely determined by the Scheduler class.

@yield_task, a process can automatically discard execution through system call Sched_yield, at which point the kernel invokes the Yield_task function of the Scheduler class.

@check_preempt_curr, this function is called to preempt the current process, if necessary.

@pick_next_task, to select the next process that is about to run

@put_prev_task, call before using a different process to replace the currently running process

@set_curr_task, called when the scheduling policy of the current process changes, you need to call this function to change the current task of the CPU

@task_tick, called by the periodic scheduler each time the periodic scheduler is activated

@new_task, when the system creates a new task, it needs to be notified by this function to the Scheduler class


Data

An instance of the structure is embedded in each ready queue of the main scheduler:

230/* cfs-related fields in a runqueue/231 struct CFS_RQ {232 struct load_weight     load;
 233     unsigned long nr_running;
 234 
 235     u64 Exec_clock;
 236     u64 Min_vruntime;
 237 
 238     struct rb_root tasks_timeline;
 239     struct Rb_node *rb_leftmost;     struct Rb_node *rb_load_balance_curr;
 241/     * ' Curr ' points to currently running entity in this CFS_RQ.
 242      * It is set to NULL otherwise (i.e when none are currently running).
 243      * *
 244     struct sched_entity *curr;
 245 
 246     unsigned long nr_spread_over;
 262};

Nr_running calculates the number of running processes on a queue, and load maintains the cumulative value of all of these processes. We'll compute the virtual clock by load.

Exec_clock only has the actual running time of statistics.

Min_vruntime calculates the minimum virtual run time for all processes on the queue.

Tasks_timeline is the tree node of the red and Black tree, which manages all processes, sorts them according to the virtual run time of these processes, and the leftmost process is the process with the smallest virtual run time and the process that is most needed to be invoked.

Rb_leftmost point to the leftmost node of the tree, we can actually find this node by traversing the Tasks_timeline.

Curr a dispatch entity that points to the current executable process in CFS_RQ


The working principle of CFS

The fully fair scheduling algorithm relies on the virtual clock to measure the CPU time that the waiting process can get in a perfectly fair system. However, there is no representation of the virtual clock in the data structure, because the virtual clock can be computed from the actual clock and the load weight associated with each process.

All calculations related to the virtual clock are performed in Update_curr, which are called in various places in the system.

336 static void Update_curr (struct CFS_RQ *cfs_rq) 337 {338 struct sched_entity *curr     = cfs_rq->curr;
  339     U64 now = rq_of (CFS_RQ)->clock;     unsigned long delta_exec;
 341 
 342     if (unlikely (!curr))
 343 return         ;
 344 345/* 346 * Get the amount of "the" Current     task is      running
 347      * Since the last Ti Me we changed load (this cannot
 348      * overflow on \ Bits):
 349
 /delta_exec     = (unsign Ed long) (Now-curr->exec_start);
 351 
 352     __update_curr (CFS_RQ, Curr, delta_exec);
 353     Curr->exec_start = now;
 354 
 355     if (Entity_is_task (Curr)) {356 struct task_struct *curtask         = task_of (curr);
 357 
 358         cpuacct_charge (Curtask, delta_exec);
 359     }
 360}

339 rq_of (CFS_RQ)->clock The clock that implements the ready queue itself, and updates the clock value each time the periodic scheduler is invoked

Curr->exec_start saves the last time the load was changed, noting that it was not the last time the process was run. The current process may occur multiple times during one run Update_curr


__update_curr

 304 static inline void 305 __update_curr (struct CFS_RQ *cfs_rq, struct sched_entity *curr, 306 unsigned long
 Delta_exec) 307 {308 unsigned long delta_exec_weighted;
 309 U64 Vruntime;
 310 311 schedstat_set (Curr->exec_max, Max ((u64) delta_exec, Curr->exec_max));
 312 313 Curr->sum_exec_runtime + = delta_exec;
 Schedstat_add (Cfs_rq, Exec_clock, delta_exec);
 315 delta_exec_weighted = delta_exec; 316 if (Unlikely (Curr->load.weight!= nice_0_load)) {317 delta_exec_weighted = Calc_delta_fair (delta_exec
 _weighted, 318 &curr->load);
 319} curr->vruntime + + = delta_exec_weighted; 321 322/* 323 * maintain cfs_rq->min_vruntime to being a monotonic increasing 324 * value tracking the
 Leftmost vruntime in the tree.                 325 */326 if (First_fair (CFS_RQ)) {327 vruntime = Min_vruntime (Curr->vruntime, 328 __pick_next_entity(CFS_RQ)->vruntime);
 329} else Vruntime = curr->vruntime;
 331 332 cfs_rq->min_vruntime = 333 Max_vruntime (cfs_rq->min_vruntime, vruntime);
 334}

313 Sum_exec_runtime The CPU time cumulative value that the process consumes, @delta_exec is the difference between the last time the load statistic was updated, both of which are real.

316 if the priority of the process is (nice = 0), then the virtual time and physical time are the same, otherwise the virtual execution time is computed by calc_delta_mine

326 First_fait Detect if there is a leftmost node on the tree, that is, whether there are processes waiting on the tree for scheduling

332 Cfs_rq->min_vruntime is a monotonous increase.

During the running process, the vruntime of the process scheduling entity is increased monotonically, the higher the priority process, the slower the increase, so they move to the right speed is slower. The greater the chance of being dispatched.


Deferred tracking

The kernel has an inherent concept called scheduling latency, which guarantees that each process is at least one time interval to run.

sysctl_sched_latency

Parameters are used to control this behavior, and the default definition is 20ms, which can be controlled by/proc/sys/kernel/sched_latency_ns.

Sched_nr_latency

Controls the maximum number of activities processed during a delay period. If the data for the active process exceeds the upper limit, the delay cycle is also proportional to the linear extension.

__sched_period

The length of the delay period is usually sysctl_sched_latency, but if more processes are running, the value is calculated by using the following formula:

__sched_period = sysctl_sched_latency * nr_running/sched_nr_latency


During a delay period, the time of the delay period is allocated between the active processes by taking into account the weights of each process. For a given process that is represented by a dispatch entity, the allotted time is calculated as follows.

Static U64 sched_slice (struct Cfs_rq *cfs_rq, struct sched_entity *se)
{
    U64 slice = __sched_period (cfs_rq-> nr_running);

    Slice *= se->load.weight;
    Do_div (Slice, cfs_rq->load.weight);

    return slice;
}




Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.