Как ядро ​​Linux распределяет ЦП между процессами/потоками пространства пользователя и задачами/заданиями ядра

Вы пропустили завершающую точку с запятой, которая должна быть экранирована из оболочки, например:\;или ';'.

На справочной странице find говорится следующее:

-exec command ;

Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command

...

Внимание сюда:

until an argument consisting of ';' is encountered.

...

The string '{}' is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is alone, as in some versions of find. Both of these constructions might need to be escaped (with a '\') or quoted to protect them from expansion by the shell.

...

4
28.10.2019, 19:50
2 ответа

How this works?

(прокрутите до конца оригинальный «планировщик» Linux)

Это совершенно невозможно объяснить простыми словами. Даже трудно дать определение упомянутым вами терминам (процесс, поток, задача, ядро/пользователь ).

I know that the scheduler schedules different processes based on priority/time slicing.

Разбивка времени на одноядерном одноядерном процессоре — это то, как он начинается для Linux и процессоров x86 -. Также DOS и первая MS -Windows. Но Linux реализовал защищенный режим 386, чтобы изолировать «параллельные» процессы, возникающие в результате этого разделения. Вместе с подкачкой памяти это дает прочную основу для «многозадачного -задания», а «хорошее» значение является простым расширением принципа циклического -перебора.

Но затем возникает «узкое место» ЦП -ОЗУ :после каждого переключения контекста между процессами, инструкции и данные должны найти свой путь из ОЗУ в кэш ЦП (с ). Это побочный -эффект четкого разделения процессов.

kernel/Kconfig.hzпредлагает срезы от 100 до 1000 Гц; вот информация для 300 герц (300 переключений контекста в секунду):

300 Hz is a good compromise choice allowing server performance while also showing good interactive responsiveness even on SMP and NUMA systems and exactly dividing by both PAL and NTSC frame rates for video and multimedia work.

SMP — это способ одновременного выполнения нескольких таких слайсов, а NUMA можно использовать для организации основной памяти таким образом, чтобы она была в пределах досягаемости каждого процессора. Хороший планировщик должен найти компромисс -между пропускной способностью и скоростью отклика -очень быстро и надежно.

С потоками как LWP s (через pthread или clone ()вместо разветвления ())существует стандартный способ выполнения кода с меньшими затратами на переключение контекста. Основным отличием является стек, то есть локальные переменные, которые разделяют потоки.

Планировщик должен не только запускать и засыпать процессы, но и выполнять «сложную» математику, как вkernel/sched/fair.c:

   /*
     * Distribute memory according to CPU & memory use on each node,
     * with 3/4 hysteresis to avoid unnecessary memory migrations:
     *
     * faults_cpu(dst)   3   faults_cpu(src)
     * --------------- * - > ---------------
     * faults_mem(dst)   4   faults_mem(src)
     */

Все это планировщик должен делать между процессами.

«Рабочие процессы ядра» под pid #2 [kthreadd]— это некоторые вспомогательные процессы, на которые опирается планировщик,и они активируются по запросу. Возьмите, например. "[khungtaskd]" :Это не проблема синхронизации миллисекунд, поэтому планировщик может передать это задание на аутсорсинг.


Чтобы понять всю сложность всего этого, вы можете погрузиться в другие (не -x86 _64 )архитектуры :RISC :PowerPC, Sparc, ARM. Посмотрите на «Саммит» из Ок-Риджа :4096 «узлов», каждый из которых имеет 2 ЦП (и 6 графических процессоров ), каждый ЦП имеет 24 ядра, каждое ядро ​​​​может «иметь» 4 потока. И все это работает на одном ядре RH Linux, с кучей дополнительных слоев («супервизор», NUMA, «интерконнект» ).

И совсем недавно я увидел, что вершина новостей :достигла более 1 ExaFlop в анализе ДНК -. Это означает :все 4000 x 2 x 22 x 4 потоков были заняты «простой» обработкой C, G, T и A (некоторая программа Genome должна разделить данные и создать процессы и/или потоки ).

Это противоположно тому, как многозадачность -в Linux начиналась :как способ запуска нескольких процессов на одном процессоре. Планировщик должен учитывать обе крайности.

1990 Linux был «современным полноценным -полноценным [клоном] Unix» с «настоящей» многозадачностью -и «правильным» [виртуальным] управлением памятью)(см.Documentation/admin-guide/README.rst)

С современными многоядерными -и многопоточными -ЦП ОС также должна предлагать более точную детализацию , чем просто процессы. Если вы покупаете процессор под названием «Threadripper», вы ожидаете, что он будет делать больше, чем просто переключаться между процессами.

На wikichip.org есть очень красивые изображения различных ядер ЦП с множеством пояснений ("выстрелов" ). Планировщик — это часть операционной системы, ответственная за эффективное размещение инструкций и данных в этих радужных -блоках.

С этими физическими ядрами, кэшами и контроллерами памяти в затылке, подкрепленными википедией,вы можете получить хорошее представление о том, что делает планировщик, взглянув на код C в kernel/sched/.

    /*
     * If there's no RR tasks, but FIFO tasks, we can skip the tick, no
     * forced preemption between FIFO tasks.
     */

Это изcore.c-Я мало что понимаю, но это показывает, что на ваш вопрос нет простого ответа. Либо упрощаешь и искажаешь, либо теряешься в 1000 деталях.

30 лет назад было немного проще :Одна маленькая (, но ХОРОШО ЗАПРОГРАММИРОВАННАЯ :-)функция расписания ()вkernel/schedule.c

/*
 *  'schedule()' is the scheduler function. This is GOOD CODE! There
 * probably won't be any reason to change this, as it should work well
 * in all circumstances (ie gives IO-bound processes good response etc).
 * The one thing you might take a look at is the signal-handler code here.
 *
 *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
 * tasks can run. It can not be killed, and it cannot sleep. The 'state'
 * information in task[0] is never used.
 */

Этот абстракционизм «Задача 0» — это то, что удерживает pid #1 в pid #xxxx (рабочую очередь )работающую -, но похоже, что все это из первых версий Linux исчезло / имеет много эволюционировал.


/* this is the scheduler proper: */

        while (1) {
                c = -1;
                next = 0;
                i = NR_TASKS;
                p = &task[NR_TASKS];
                while (--i) {
                        if (!*--p)
                                continue;
                        if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
                                c = (*p)->counter, next = i;
                }
                if (c) break;
                for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
                        if (*p)
                                (*p)->counter = ((*p)->counter >> 1) +
                                                (*p)->priority;
        }
        switch_to(next);

С p в качестве массива задач, a while (1 )и некоторых счетчиков основная идея довольно проста.

Это (*p)->state == TASK_RUNNINGпроверяется каждый раз, здесь, в linux 0.01. «Правильно рабочая очередь» будет блокировать не -бегунов в отдельном списке. Небольшой файл kernel/sched.c превратился в kernel/sched/*размером 1 МБ.


kernel/sched/ также содержитclock.c:

 * ######################### BIG FAT WARNING ##########################
 * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can #
 * # go backwards !!                                                  #
 * ####################################################################

-2
27.01.2020, 21:06

Задачи ядра, которые не запускаются «в процессе» (для обслуживания системного вызова или прерывания ), сами обрабатываются как отдельные процессы, и вы можете увидеть их в выводе ps:

. ]
root         2  0.0  0.0      0     0 ?        S    Sep16   0:02 [kthreadd]
root         3  0.0  0.0      0     0 ?        I<   Sep16   0:00 [rcu_gp]
root         4  0.0  0.0      0     0 ?        I<   Sep16   0:00 [rcu_par_gp]
root         6  0.0  0.0      0     0 ?        I<   Sep16   0:00 [kworker/0:0H-kblockd]
root         8  0.0  0.0      0     0 ?        I<   Sep16   0:00 [mm_percpu_wq]
root         9  0.0  0.0      0     0 ?        S    Sep16   9:11 [ksoftirqd/0]
root        10  0.2  0.0      0     0 ?        I    Sep16 173:25 [rcu_sched]
root        11  0.0  0.0      0     0 ?        I    Sep16   0:00 [rcu_bh]
root        12  0.0  0.0      0     0 ?        S    Sep16   0:20 [migration/0]
root        14  0.0  0.0      0     0 ?        S    Sep16   0:00 [cpuhp/0]
root        15  0.0  0.0      0     0 ?        S    Sep16   0:00 [cpuhp/1]

Эти процессы планируются таким же образом, как и процессы, с которыми вы более знакомы.

Общим шаблоном для таких задач является workqueues ; документация ядра для них довольно хороша, я рекомендую вам прочитать ее, если вам интересна эта тема.

1
27.01.2020, 21:06

Теги

Похожие вопросы