Вопрос по linux, real-time, scheduling, performance – Как защитить процессор от планировщика Linux (не допускать планирования потоков на этот процессор)?

20

Можно использоватьsched_setaffinity закрепить поток на процессоре, увеличив производительность (в некоторых ситуациях)

Со страницы руководства Linux:

Restricting a process to run on a single CPU also avoids the performance cost caused by the cache invalidation that occurs when a process ceases to execute on one CPU and then recommences execution on a different CPU

Кроме того, если я хочу получить ответ в режиме реального времени, я могу изменить политику планировщика для этого потока наSCHED_FIFOи повысить приоритет до некоторого высокого значения (доsched_get_priority_max), что означает, что рассматриваемый поток должен всегда опережать любой другой поток, выполняющийся на его процессоре, когда он становится готовым.

Однако в этот момент поток, работающий на процессоре, который поток с реальным временем только что очистил, возможно, изгнал бы большую часть записей кэша уровня 1 потока в реальном времени.

Мои вопросы следующие:

  1. Is it possible to prevent the scheduler from scheduling any threads onto a given cpu? (eg: either hide the cpu completely from the scheduler, or some other way)
  2. Are there some threads which absolutely have to be able to run on that cpu? (eg: kernel threads / interrupt threads)
  3. If I need to have kernel threads running on that cpu, what is a reasonable maximum priority value to use such that I don't starve out the kernel threads?
@HongZhou - я нашел утилиту cpuset, которая делает именно то, что я хочу - посмотрите мой добавленный ответ Steve Lorimer
Спасибо, что поделились! Hong Zhou
Здравствуйте, у меня тоже такой же вопрос. Вы узнали что-нибудь новое по этому поводу? Hong Zhou

Ваш Ответ

3   ответа
34

Cpusets,утилита python cpuset облегчает их настройку.

Basic concepts

3 cpusets

root: present in all configurations and contains all cpus (unshielded) system: contains cpus used for system tasks - the ones which need to run but aren't "important" (unshielded) user: contains cpus used for "important" tasks - the ones we want to run in "realtime" mode (shielded)

shield Команда управляет этими 3 процессорами.

Во время настройки он перемещает все подвижные задачи в неэкранированный процессор (system) и во время демонтажа перемещает все подвижные задачи вroot cpuset. После установки подкоманда позволяет перемещать задачи вshield (user) cpuset и, кроме того, для перемещения специальных задач (потоков ядра) изroot вsystem (и, следовательно, изuser cpuset).

Commands:

Сначала мы создаем щит. Естественно, расположение щита будет зависеть от машины / задачи. Например, скажем, у нас есть 4-ядерный компьютер не-NUMA: мы хотим посвятить3 cores to the shield, и уходи1 core for unimportant tasks; поскольку это не NUMA, нам не нужно указывать какие-либо параметры узла памяти, и мы оставляем потоки ядра работающими вroot процессор (то есть: через все процессоры)

$ cset shield --cpu 1-3

Некоторые потоки ядра (те, которые не привязаны к конкретному процессору) могут быть перемещены вsystem cpuset. (В общем случае не рекомендуется переносить потоки ядра, связанные с конкретным процессором)

$ cset shield --kthread on

Теперь давайте перечислим, что работает на экране (user) или неэкранированный (system) cpusets: (-v для подробного, который будет перечислять имена процессов) (добавить 2-й-v для отображения более 80 символов)

$ cset shield --shield -v
$ cset shield --unshield -v -v

Если мы хотим остановить щит (демонтаж)

$ cset shield --reset

Теперь давайте выполним процесс в щите (команды следующие'--' передаются команде, которая будет выполнена, а неcset)

$ cset shield --exec mycommand -- -arg1 -arg2

Если у нас уже есть запущенный процесс, который мы хотим переместить в экран (обратите внимание, что мы можем перемещать несколько процессов, передавая разделенный запятыми список или диапазоны (любой процесс в диапазоне будет перемещен, даже если есть пробелы))

$ cset shield --shield --pid 1234
$ cset shield --shield --pid 1234,1236
$ cset shield --shield --pid 1234,1237,1238-1240

Advanced concepts

cset set/proc - это дает вам лучший контроль над процессорами

Set

Создание, настройка, переименование, перемещение и уничтожение процессоров

Commands

Создайте процессор, используя процессор 1-3, используйте узел 1 NUMA и назовите его «my_cpuset1».

$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1

Изменить & quot; my_cpuset1 & quot; использовать только процессоры 1 и 3

$ cset set --cpu=1,3 --mem=1 --set=my_cpuset1

Уничтожить процессор

$ cset set --destroy --set=my_cpuset1

Переименовать существующий процессор

$ cset set --set=my_cpuset1 --newname=your_cpuset1

Создать иерархический процессор

$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1

Список существующих процессоров (глубина уровня 1)

$ cset set --list

Список существующих процессоров и их потомков

$ cset set --list --set=my_cpuset1

Перечислите все существующие процессоры

$ cset set --list --recurse

Proc

Управление потоками и процессами

Commands

Список задач, выполняемых в процессоре

$ cset proc --list --set=my_cpuset1 --verbose

Выполнить задачу в процессоре

$ cset proc --set=my_cpuset1 --exec myApp -- --arg1 --arg2

Перемещение задачи

$ cset proc --toset=my_cpuset1 --move --pid 1234
$ cset proc --toset=my_cpuset1 --move --pid 1234,1236
$ cset proc --toset=my_cpuset1 --move --pid 1238-1340

Перемещение задачи и всех ее братьев и сестер

$ cset proc --move --toset=my_cpuset1 --pid 1234 --threads

Переместить все задачи из одного процессора в другой

$ cset proc --move --fromset=my_cpuset1 --toset=system

Переместить не закрепленные потоки ядра в процессор

$ cset proc --kthread --fromset=root --toset=system

Принудительно перемещайте потоки ядра (включая те, которые прикреплены к конкретному процессору) в процессор (обратите внимание: это может иметь пагубные последствия для системы - убедитесь, что вы знаете, что делаете)

$ cset proc --kthread --fromset=root --toset=system --force

Hierarchy example

Мы можем использовать иерархические процессоры для создания приоритетных группировок

Create a system cpuset with 1 cpu (0) Create a prio_low cpuset with 1 cpu (1) Create a prio_met cpuset with 2 cpus (1-2) Create a prio_high cpuset with 3 cpus (1-3) Create a prio_all cpuset with all 4 cpus (0-3) (note this the same as root; it is considered good practice to keep a separation from root)

Для достижения вышеизложенного вы создаете prio_all, а затем создаете подмножество prio_high в prio_all и т. Д.

$ cset set --cpu=0 --set=system
$ cset set --cpu=0-3 --set=prio_all
$ cset set --cpu=1-3 --set=/prio_all/prio_high
$ cset set --cpu=1-2 --set=/prio_all/prio_high/prio_med
$ cset set --cpu=1 --set=/prio_all/prio_high/prio_med/prio_low
Этот ответ потрясающий. Спасибо!
5

как cset, который, похоже, не имеет фантастического уровня поддержки от Redhat):

1) Все наборы задач, включая PID 1 - красиво и легко (но, как утверждается, я сам никогда не сталкивался с проблемами - может привести к неэффективности планировщика). Сценарий ниже (который должен запускаться с правами root) запускает набор задач на всех запущенных процессах, включая init (pid 1); это будет привязывать все запущенные процессы к одному или нескольким «нежелательным ядрам», и, также прикрепляя init, будет гарантировать, что любые будущие процессы также будут запущены в списке «нежелательных ядер»:

#!/bin/bash

if [[ -z $1 ]]; then
  printf "Usage: %s '<csv list of cores to set as junk in double quotes>'", $0
  exit -1;
fi

for i in `ps -eLfad |awk '{ print $4 } '|grep -v PID | xargs echo `; do 
   taskset -pc $1 $i;
done

2) использовать параметр ядра isolcpus (здесь документация отhttps://www.kernel.org/doc/Documentation/kernel-parameters.txt):

isolcpus=   [KNL,SMP] Isolate CPUs from the general scheduler.
            Format:
            <cpu number>,...,<cpu number>
            or
            <cpu number>-<cpu number>
            (must be a positive range in ascending order)
            or a mixture
            <cpu number>,...,<cpu number>-<cpu number>

        This option can be used to specify one or more CPUs
        to isolate from the general SMP balancing and scheduling
        algorithms. You can move a process onto or off an
        "isolated" CPU via the CPU affinity syscalls or cpuset.
        <cpu number> begins at 0 and the maximum value is
        "number of CPUs in system - 1".

        This option is the preferred way to isolate CPUs. The
        alternative -- manually setting the CPU mask of all
        tasks in the system -- can cause problems and
        suboptimal load balancer performance.

Я использовал эти два плюс механизмы cset для нескольких проектов (кстати, прошу прощения за вопиющее саморекламу :-)), я только что подал патент на инструмент под названиемPontus Vision ThreadManager  это предлагает оптимальные стратегии закрепления для любой данной платформы x86 для любой заданной рабочей нагрузки программного обеспечения; после тестирования на клиентском сайте я получил действительно хорошие результаты (снижение пиковых задержек на 270%), так что стоит заняться пиннингом и изоляцией процессора.

0

используя cgroups. У меня есть машина Fedora 28, и RedHat / Fedora хотят, чтобы вы использовалиsystemd-run, но я не смог найти эту функцию там. Я хотел бы знать, как это сделать, используяsystemd-runЕсли кто-нибудь захочет просветить меня.

Допустим, я хочу исключить мой четвертый ЦП (из ЦП 0-3) из планирования и переместить все существующие процессы в ЦП 0-2. Затем я хочу поставить процесс на CPU 3 сам по себе.

sudo su -
cgcreate -g cpuset:not_cpu_3
echo 0-2 > /sys/fs/cgroup/cpuset/not_cpu_3/cpuset.cpus
# This "0" is the memory node. See https://utcc.utoronto.ca/~cks/space/blog/linux/NUMAMemoryInfo
# for more information *
echo 0 > /sys/fs/cgroup/cpuset/not_cpu_3/cpuset.mems
Specifically, on your machine you'll want to review /proc/zoneinfo and the /sys/devices/system/node heirarchy. Getting the proper node information is left as an exercise for the reader.

Теперь, когда у нас есть наша cgroup, нам нужно создать нашу изолированную cgroup CPU 3:

cgcreate -g cpuset:cpu_3
echo 3 > /sys/fs/cgroup/cpuset/cpu_3/cpuset.cpus
# Again, the memory node(s) you want to specify.
echo 0 > /sys/fs/cgroup/cpuset/cpu_3/cpuset.mems

Поместите все процессы / потоки наnot_cpu_3 контрольная группа:

for pid in $(ps -eLo pid) ; do cgclassify -g cpuset:not_cpu_3 $pid; done

Обзор:

ps -eL k psr o psr,pid,tid,args | sort | cut -c -80

НОТА! Процессы в настоящее время во снеwill not move, Они должны быть разбужены, чтобы планировщик поместил их в другой процессор. Чтобы увидеть это, выберите ваш любимый спящий процесс из приведенного выше списка - процесс, скажем, веб-браузер, который, как вы думали, должен быть на ЦПУ 0-2, но он все еще на 3. Используя свой идентификатор потока из приведенного выше списка, выполните :

kill -CONT <thread_id>

пример

kill -CONT 9812

Повторите команду ps и обратите внимание, что она перемещена на другой процессор.

ДВОЙНОЕ ПРИМЕЧАНИЕ! Некоторые темы ядраcannot и не будет двигаться! Например, вы можете заметить, что каждый процессор имеет поток ядра[kthreadd] в теме. Назначение процессов в cgroups работает для процессов в пространстве пользователя, а не для потоков ядра. Это жизнь в мире многозадачности.

Теперь для перемещения процесса и всех его дочерних элементов в группу управления cpu_3:

pid=12566 # for example
cgclassify -g cpuset:cpu_3 $pid
taskset -c -p 3 $pid

Опять же, если$pid находится в спящем режиме, вам нужно разбудить его для того, чтобы процессорный процессор действительно имел место.

Чтобы отменить все это, просто удалите созданные вами группы. Все вернутся в корневую группу:

cgdelete -r cpuset:cpu_3
cgdelete -r cpuset:not_cpu_3

Нет необходимости перезагружаться.

(Извините, я не понимаю 3-й вопрос из оригинального постера. Я не могу комментировать это.)

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