Odpověď je použít cpusets. Nástroj python cpuset usnadňuje jejich konfiguraci.
Základní pojmy
3 cpussety
root
:přítomen ve všech konfiguracích a obsahuje všechny procesory (nestíněné )system
:obsahuje procesor používaný pro systémové úlohy – ty, které je třeba spustit, ale nejsou „důležité“ (nestíněné )user
:obsahuje procesor používaný pro „důležité“ úlohy – ty, které chceme spouštět v režimu „v reálném čase“ (stíněný )
shield
příkaz spravuje tyto 3 cpussety.
Během nastavení přesune všechny pohyblivé úlohy do nechráněné cpuset (system
) a během teardown přesune všechny pohyblivé úlohy do root
cpuset. Po nastavení vám dílčí příkaz umožňuje přesunout úlohy do štítu (user
) cpuset a navíc přesunout speciální úlohy (vlákna jádra) z root
na system
(a proto mimo user
cpuset).
Příkazy:
Nejprve vytvoříme štít. Rozložení štítu bude přirozeně závislé na stroji/úloze. Řekněme například, že máme 4jádrový počítač bez NUMA:chceme věnovat 3 jádra štítu a ponechat 1 jádro pro nedůležité úkoly; protože to není NUMA, nemusíme zadávat žádné parametry paměťového uzlu a necháváme vlákna jádra spuštěná v root
cpuset (tj.:napříč všemi procesory)
$ cset shield --cpu 1-3
Některá vlákna jádra (ta, která nejsou vázána na konkrétní procesor) lze přesunout do system
cpuset. (Obecně není dobrý nápad přesouvat vlákna jádra, která byla navázána na konkrétní procesor)
$ cset shield --kthread on
Nyní si uveďme, co běží ve štítu (user
) nebo nestíněné (system
) cpusets:(-v
pro verbose, kde budou uvedeny názvy procesů) (přidejte 2. -v
pro zobrazení více než 80 znaků)
$ cset shield --shield -v
$ cset shield --unshield -v -v
Pokud chceme zastavit štít (trhání)
$ cset shield --reset
Nyní provedeme proces ve štítu (příkazy následující '--'
jsou předány příkazu, který má být proveden, nikoli cset
)
$ cset shield --exec mycommand -- -arg1 -arg2
Pokud již máme spuštěný proces, který chceme přesunout do štítu (všimněte si, že můžeme přesunout více procesů předáním čárkou odděleného seznamu nebo rozsahů (všechny procesy v rozsahu budou přesunuty, i když jsou mezery))
$ cset shield --shield --pid 1234
$ cset shield --shield --pid 1234,1236
$ cset shield --shield --pid 1234,1237,1238-1240
Pokročilé koncepty
cset set/proc
- tyto vám poskytují jemnější kontrolu nad cpussety
Nastavit
Vytvářejte, upravujte, přejmenovávejte, přesouvejte a ničte cpusets
Příkazy
Vytvořte cpuset pomocí cpus 1-3, použijte NUMA uzel 1 a nazvěte jej "my_cpuset1"
$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1
Změňte "my_cpuset1" tak, aby používal pouze cpus 1 a 3
$ cset set --cpu=1,3 --mem=1 --set=my_cpuset1
Zničte cpuset
$ cset set --destroy --set=my_cpuset1
Přejmenujte existující cpuset
$ cset set --set=my_cpuset1 --newname=your_cpuset1
Vytvořte hierarchický cpuset
$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1
Seznam existujících cpussetů (hloubka úrovně 1)
$ cset set --list
Seznam existujících cpuset a jejich potomků
$ cset set --list --set=my_cpuset1
Seznam všech existujících cpuset
$ cset set --list --recurse
Proc
Správa vláken a procesů
Příkazy
Seznam úloh spuštěných v cpuset
$ cset proc --list --set=my_cpuset1 --verbose
Proveďte úlohu v cpuset
$ cset proc --set=my_cpuset1 --exec myApp -- --arg1 --arg2
Přesunutí úkolu
$ 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
Přesunutí úkolu a všech jeho sourozenců
$ cset proc --move --toset=my_cpuset1 --pid 1234 --threads
Přesunout všechny úlohy z jednoho cpusetu do druhého
$ cset proc --move --fromset=my_cpuset1 --toset=system
Přesunout nepřipnutá vlákna jádra do cpuset
$ cset proc --kthread --fromset=root --toset=system
Vynuceně přesouvejte vlákna jádra (včetně těch, která jsou připojena ke konkrétnímu procesoru) do cpuset (poznámka:to může mít pro systém hrozné důsledky – ujistěte se, že víte, co děláte)
$ cset proc --kthread --fromset=root --toset=system --force
Příklad hierarchie
K vytvoření prioritních seskupení můžeme použít hierarchické cpusets
- Vytvořte
system
cpuset s 1 cpu (0) - Vytvořte
prio_low
cpuset s 1 cpu (1) - Vytvořte
prio_met
cpuset se 2 cpus (1-2) - Vytvořte
prio_high
cpuset se 3 cpus (1-3) - Vytvořte
prio_all
cpuset se všemi 4 cpusy (0-3) (to je stejné jako root; považuje se za dobrou praxi zachovat oddělení od rootu)
K dosažení výše uvedeného vytvoříte prio_all a poté podmnožinu prio_high pod prio_all atd
$ 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
Existují dva další způsoby, jak to udělat (ačkoli ne tak elegantní jako cset, který, jak se zdá, nemá fantastickou úroveň podpory od Redhat):
1) Nastavit vše včetně PID 1 – pěkné a snadné (ale údajně – sám jsem nikdy žádné problémy neviděl – může způsobit neefektivitu plánovače). Níže uvedený skript (který musí být spuštěn jako root) spouští taskset na všech běžících procesech, včetně init (pid 1); to připne všechny běžící procesy k jednomu nebo více „junk cores“ a tím, že také připnete init, zajistí, že všechny budoucí procesy budou také spuštěny v seznamu „junk cores“:
#!/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) použijte parametr jádra isolcpus (zde je dokumentace z 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.
Použil jsem tyto dva plus mechanismy cset pro několik projektů (mimochodem, omluvte tu nehoráznou sebepropagaci :-)), právě jsem podal patent na nástroj nazvaný Pontus Vision ThreadManager, který přichází s optimálními strategiemi připínání pro všechny daná platforma x86 pro jakékoli dané softwarové pracovní zatížení; po otestování na zákaznickém webu jsem získal opravdu dobré výsledky (270% snížení špičkových latencí), takže se vyplatí provést připnutí a izolaci CPU.