Date |
Kernel version |
Architecture |
author |
GitHub |
CSDN |
2016-6-29 |
Linux-4.6 |
X86 & Arm |
Gatieme |
Linuxdevicedrivers |
Linux process management and scheduling |
We mentioned earlier that Linux has two methods of activating the Scheduler: the Core Scheduler and
One is straightforward, such as a process that intends to sleep or abandons the CPU for other reasons
The other is through the periodic mechanism, at a fixed frequency to run, from time to test whether it is necessary
Thus, the kernel provides two scheduler Master Scheduler , the periodic scheduler , respectively, the implementation of the work, the two together to form the Core Scheduler (Core Scheduler), also known as the General scheduler ( Generic scheduler).
They all allocate CPU time according to the priority of the process, so this process is called the priority dispatch, we will mainly explain the design of the core scheduler and the implementation of the priority scheduling in this section.
and our periodic scheduler activates a periodic scheduling method that is responsible for the current process scheduling class at a fixed frequency to ensure the concurrency of the system
1 Foreground review
First of all, let's briefly review the contents of the previous sub-
1.1 Process scheduling
A unique description of each process is saved in memory and is connected to other processes through several constructs.
This is the case with the scheduler , whose task is to share CPU time between programs, creating the illusion of parallel execution, which is divided into two different parts, one involving a scheduling strategy and the other involving context switching .
The kernel must provide a way to share CPU time as equitably as possible between processes, while at the same time taking into account different task priorities.
The general principle of the scheduler is to provide maximum fairness to each process in the system, based on the computing power required to allocate, or, from another point of view, to ensure that no process has been mistreated.
1.2 Classification of the process
Linux separates processes into real-time and non-real -time processes, where non-real-time processes are further divided into interactive processes and batch processes
Linux uses different scheduling strategies based on the different classifications of the process.
For real-time processes, the FIFO, Round Robin or earliest Deadline first (EDF) initial deadline scheduling algorithm | is used for the scheduling strategy.
For normal processes, the CFS is used to dispatch the complete Fair scheduler
1.3 The evolution of Linux Scheduler
Field |
version |
An O (n) Initial scheduling algorithm |
linux-0.11~2.4 |
O (1) Scheduler |
linux-2.5 |
CFS Scheduler |
Linux-2.6~ to present |
1.4 Linux Scheduler composition
2 Scheduler
Scheduling can be activated in two ways
One is straightforward, such as a process that intends to sleep or abandons the CPU for other reasons
The other is through the periodic mechanism, at a fixed frequency to run, from time to test whether it is necessary
So the current Linux scheduler consists of two schedulers: the Main Scheduler , the periodic scheduler (both collectively referred to as the Universal Scheduler (Generic Scheduler) or the core Scheduler Scheduler))
And each scheduler consists of two content: the dispatch framework (which is essentially two function frames) and the Scheduler class
6 Scheduling strategies
The Linux kernel currently implements a 6 scheduling strategy (the scheduling algorithm) for scheduling different types of processes or supporting certain special functions
Sched_normal and Sched_batch scheduling ordinary non-real-time processes
Sched_fifo and SCHED_RR and sched_deadline use different scheduling strategies to schedule real-time processes
Sched_idle calls the idle process when the system is idle.
5 Scheduler Classes
According to its scheduling strategy, 5 Scheduler classes are implemented, and a scheduler class can dispatch a class of processes with one or more scheduling strategies, or it can be used in special cases or in the process of scheduling special functions.
The priority order of the processes to which they belong is
stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class
3 Dispatch Entities
The scheduler is not limited to the scheduling process, but can also dispatch larger entities, such as implementing group scheduling.
This general requirement is that the scheduler does not directly manipulate processes, but instead processes the scheduler entities, so a common data structure is required to describe the scheduling entity, the seched_entity structure, which actually represents a scheduling object that can be a process or a process group.
Linux defines 3 scheduled entities of type seched_entity for current and non-real-time processes that can be scheduled
Sched_dl_entity Real-time scheduling entity using EDF algorithm
Sched_rt_entity Real-time scheduling entity using Roound-robin or FIFO algorithm Rt_sched_class
Sched_entity scheduling entity of ordinary non-real-time process using CFS algorithm
2 Periodic scheduler
The periodic scheduler is implemented in the Scheduler_tick. If the system is active, the kernel automatically calls the function at frequency Hz. If there is no near-awaited dispatch, the kernel shuts down the scheduler to reduce power consumption when the computer is under-supplied. This is important for the power management of our embedded devices or mobile terminal devices.
2.1 Cycle Scheduler Main flow
The Scheduler_tick function is defined in kernel/sched/core.c, L2910, which has two main tasks
Update related statistics
Manages the statistics in the kernel related to the overall system and the scheduling of individual processes. The main operations performed during this period are the various counters +1
Activates the periodic scheduling method that is responsible for the current process scheduling class
Check if the process execution time exceeds its corresponding ideal_runtime, and if it is exceeded, tell the system that it needs to start the main scheduler (schedule) for process switching. (Note Thread_info:preempt_count, Thread_info:flags (tif_need_resched))
/* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. * *voidScheduler_tick (void){/ * 1. Gets the global ready queue on the current CPU RQ and the currently running process Curr */ / * 1.1 in the case of SMP, get the ID of the current CPU. If it is not SMP, then return 0 * / intCPU = smp_processor_id ();/ * 1.2 Get the Global ready queue for the CPU RQ, each CPU has a ready queue RQ * / structRQ *RQ = CPU_RQ (CPU);/ * 1.3 Get the running process on the ready queue Curr * / structTask_struct *curr = rq->curr; Sched_clock_tick ();/ * 2 Update the statistics on RQ and perform periodic scheduling of the process corresponding to the scheduling class * / / * Locking * /Raw_spin_lock (&rq->lock);/ * 2.1 Update the current timestamp of RQ. Even if Rq->clock becomes the current timestamp * /Update_rq_clock (RQ);/ * 2.2 Perform periodic dispatch of the Task_tick function of the dispatch class where the current running process is located * /Curr->sched_class->task_tick (RQ, Curr,0);/* 2.3 Update the load information for RQ, i.e. the cpu_load[of the ready queue] data * Essentially, the previously stored load value in the array is moved backward one position, * The current load is recorded in the first position of the array */Update_cpu_load_active (RQ);/* 2.4 Update CPU Active count activity count * Mainly update calc_load_update*/of global CPU ready queueCalc_global_load_tick (RQ);/ * unlock * /Raw_spin_unlock (&rq->lock);/* Related to Perf count event */Perf_event_task_tick ();#ifdef CONFIG_SMP / * Current CPU is idle * /Rq->idle_balance = IDLE_CPU (CPU);/ * If it is time to do periodic load balancing then trigger SCHED_SOFTIRQ * /Trigger_load_balance (RQ);#endifRq_last_tick_reset (RQ);}
2.2 UPDATE STATISTICS
function |
Description |
definition |
Update_rq_clock |
The update of the processing-ready queue clock essentially increases the clock timestamp of the current instance of the struct RQ |
SCHED/CORE.C, L98 |
Update_cpu_load_active |
The cpu_load array that is responsible for updating the ready queue is essentially the equivalent of moving the previously stored load values in the array one position backward, and the current ready queue's compliance into the first position of the array. In addition, the function introduces some techniques of averaging to ensure that the content of the array does not render too much non-contact skip reading. |
KERNEL/SCHED/FAIR.C, L4641 |
Calc_global_load_tick |
The activity count with the new CPU, primarily the calc_load_update of updating the global CPU-ready queue |
KERNEL/SCHED/LOADAVG.C, L382 |
2.3 Periodic scheduler of the scheduling class to which the activation process belongs
Because of the modular structure of the scheduler, the main project is actually very simple, while updating the statistics, the kernel delegate the real dispatching work to the specific scheduling class method.
The kernel first finds the currently running process Curr on the ready queue and then calls the periodic scheduling method Sched_class The Curr-owned dispatch class Task_tick
That
0);
The implementation of the task_tick depends on the underlying scheduler class, such as the full Fair scheduler, which detects if the process has been running for too long to avoid too long a delay, and note that the practice here is fundamentally different from the time-slice-based scheduling method that was previously used, which we call the expiry time slice, The so-called time slice concept does not exist in the fully Fair scheduler CFS.
Currently we have 3 scheduler classes in the kernel, struct sched_entity
struct sched_rt_entity
and struct sched_dl_entity
DL, and we list their periodic dispatch functions for the scheduler classes implemented in the current kernel Task_tick
Scheduler class |
task_tick actions |
task_tick function definition |
stop_sched_class |
|
kern EL/SCHED/STOP_TASK.C, line task_tick_stop, |
dl_sched_class |
|
kernel/sched/deadline.c, line 1192, TASK_TICK_DL |
rt_sched_class |
|
/kernel/sched/rt.c, line 2227, task_t Ick_rt |
fail_sched_class |
|
kernel/sched/ FAIR.C, line 8116, Task_tick_fail |
idle_sched_class |
|
kernel/sched/idle_task.c, line, Task_tick_idle |
* If the current process is a process in a fully fair queue , then a delay interval is calculated based on the number of processes in the current ready queue, approximately each process is assigned a 2ms time, and then the time X of the process is calculated according to the percentage of the total weight in the queue. If the process executes more than X, the delay is fired, and if there is no more than X, the next process in the red-black tree ready queue has a higher priority, Curr->vruntime-leftmost->vruntime > X, which also delays scheduling
The real scheduling process for deferred scheduling is implemented in schedule, where a highest priority process is picked up according to the scheduling class order and priority.
- If the current process is a process in a real-time scheduling class: If the process is SCHED_RR, then decrements the time slice [for HZ/10], expires, inserts to the end of the queue, and fires a deferred schedule, and if it is Sched_fifo, do nothing until the process finishes executing
If the current process wants to be re-dispatched, the dispatch class method sets the tif_need_resched flag in task_struct to represent the request, and the kernel will actually complete the request in the next appropriate way.
3 Activation of the periodic scheduler 3.1 timer periodic activation scheduler
Timers are a mechanism that Linux provides for a timed service. It wakes up a process at a specific time to do some work.
After each clock interrupt of the low-resolution timer completes the global statistics update, each CPU performs the operation in a soft interrupt
- Update the current process kernel state, user state usage time on this CPU xtime_update
- Call the timer function on the CPU
- Start the periodic timer (Scheduler_tick) to complete the task on the CPU periodic scheduling work;
In a system that supports dynamic timers, the scheduler can be turned off to enter the deep sleep process; Scheduler_tick to see if the current process is running too long, and if it is, tif_need_resched the process, and then interrupts the return, calls schedule, Making a process switch operation
//http://lxr.free-electrons.com/source/arch/arm/kernel/time.c?v=4.6#L74/** Kernel system timer support.*/voidTimer_tick (void) {Profile_tick (cpu_profiling); Xtime_update (1);#ifndef CONFIG_SMPUpdate_process_times (User_mode (Get_irq_regs ()));#endif}//http://lxr.free-electrons.com/source/kernel/time/timer.c?v=4.6#L1409/ * * Called from the timer interrupt handler to charge one tick to the current * process. User_tick is 1 if the tick was user time, 0 for system. */voidUpdate_process_times (intUser_tick) {structTask_struct *p = current;/ * Note:this Timer IRQ Context must is accounted for as well. */Account_process_tick (P, User_tick); Run_local_timers (); Rcu_check_callbacks (User_tick);#ifdef config_irq_work if(IN_IRQ ()) Irq_work_tick ();#endifScheduler_tick (); Run_posix_cpu_timers (P);}
Early implementations
When Linux is initialized, the INIT_IRQ () function sets a timer period of 8253 to 10ms (a tick value). Similarly, when initializing, Time_init () sets the time interrupt vector irq0 with SETUP_IRQ (), and the Interrupt service program is timer_interrupt.
In the version 2.4 kernel and earlier versions, the interrupt processing of the timer uses the bottom-half mechanism, the registration of the bottom semi-processing function calls Sechd_init () in the Start_kernel () function, and in this function calls Init_bh (TIMER_BH, TIMER_BH) The bottom half handler function of the timer is registered. The system then calls Time_init () to register the timer's interrupt vector and interrupt handler function.
In the interrupt handler function Timer_interrupt (), it is primarily called the Do_timer () function to complete the work. The main function of the Do_timer () function is to invoke MARK_BH () to generate a soft interrupt, and then the processor will invoke the timer bottom half-handler function timer_bh () at the appropriate time. In Timer_bh (), the function of the update timer is realized. The 2.4.23 version of the Do_timer () function code is as follows (abbreviated):
void do_timer(struct pt_regs *regs){ (*(unsignedlong *)&jiffies)++; update_process_times(user_mode(regs)); mark_bh(TIMER_BH);}
After the kernel 2.6 version, the timer interrupt processing uses the soft interrupt mechanism instead of the bottom half mechanism. The clock interrupt handler function is still Timer_interrup (), Do_timer_interrupt (), Do_timer_interrupt_hook (), Do_timer (). However, the implementation of the Do_timer () function differs
void do_timer(struct pt_regs *regs){ jiffies_64++; update_process_times(user_mode(regs)); update_times();}
Implement linux-2.6 in more detail
Clock interrupt for Linux interrupt processing (i)
(original) Linux kernel process scheduling and timer implementation mechanism
Reference
Process management and scheduling 5– process scheduling, process switching principle detailed
Management and scheduling of periodic scheduler Scheduler_tick--linux process for Linux Core Scheduler (18)