Ядро Linux реализует полностью справедливый алгоритм планирования, основанный на виртуальных часах.
Каждой диспетчеризация предприятие имеет sched_entity
структуру, связанную с ним, чьим снимком выглядит как
struct sched_entity {
...
u64 exec_start;
u64 sum_exec_runtime;
u64 vruntime;
u64 prev_sum_exec_runtime;
...
}
Вышеуказанные четыре атрибута используется для отслеживания времени выполнения процесса, и с помощью этих атрибутов наряду с некоторыми другими методами (update_curr()
где они обновляются), виртуальные часы реализованы. Когда процесс присваивается процессору, exec_start
обновляется до текущего времени, а потребляемое процессорное время записывается в sum_exec_runtime
. Когда процесс снят с CPU sum_exec_runtime
, значение сохраняется в prev_sum_exec_runtime
. sum_exec_runtime
рассчитывается кумулятивно. (Значение монотонно растет).
vruntime
хранит время, прошедшее на виртуальных часах во время выполнения процесса.
Как рассчитывается vruntime
?
Игнорируя все сложные расчеты, основное понятие, как она рассчитывается является: -
vruntime += delta_exec_weighted;
delta_exec_weighted = delta_exec * (NICE_0_LOAD/load.weight);
Здесь delta_exec
разница во времени между процессом присвоенного CPU и вылетело из процессора, тогда как load.weight
является вес процесса, который зависит от приоритета (Nice Value). Обычно увеличение хорошего значения 1 для процесса означает, что он получает на 10 процентов меньше процессорного времени, что приводит к меньшему весу. процесса с NICE значением 0, вес = 1024 Процесс повторной Niced со значением 1, вес = 1024/1,25 = 820 (приблизительно)
Очки, извлеченные из вышеуказанных
- So
vruntime
увеличивается, когда процесс получает CPU
- И
vruntime
медленно увеличивается для процессов с более высоким приоритетом по сравнению с процессами с более низким приоритетом.
runqueue поддерживается в красно-черном дереве, и каждый имеет runqueue min_vruntime
переменный, связанные с ним, который содержит наименьшее среди всех vruntime
процесса в runqueue. (min_vruntime
может только увеличиваться, а не уменьшаться по мере планирования процессов).
Ключ для узла в красном черном дереве process->vruntime - min_vruntime
Когда планировщик вызывается ядро в основном берет на себя задачу, которая имеет наималейший ключ (крайний левый узел) и присваивает его процессор.
Элементы с меньшим ключом будут размещены больше влево и, таким образом, будут назначены более быстрыми темпами.
- Когда процесс запущен, его
vruntime
будет неуклонно расти, поэтому он, наконец, движется вправо в красно-черном дереве. Поскольку vruntime
увеличивается медленнее для более важных процессов, они также будут перемещаться вправо более медленно, поэтому их шанс быть запланированным больше для менее важного процесса - как и требовалось.
- Если процесс засыпает, его
vruntime
останется без изменений. Так как количество очередей min_vruntime
будет увеличиваться, процесс спящего будет больше расположен слева после пробуждения, потому что ключ (упомянутый выше) стал меньше.
Поэтому нет никаких шансов голода в качестве нижнего процесса приоритета, если лишенного процессора, будет иметь свой vruntime
маленький и, следовательно, ключ будет маленьким, так что движется слева от дерева быстро и поэтому запланировано.